We want to determine the extent to which the MIKK panel shows evidence of introgression with other medaka populations, specifically the allopatric Northern and Korean medaka strains, relative to sympatric Southern medaka strains.

Setup

library(here)
source(here::here("code", "scripts", "introgression", "source.R"))

Working directory

Working directory on EBI cluster: /hps/research1/birney/users/ian/mikk_paper

Create Singularity containers

container_dir=../sing_conts
# load Singularity (version 3.5.0)
module load singularity 

for package in $( echo r-base_4.0.4 bcftools_1.9 numpy_1.15.4 bash_3.0.22 bioconductor_3.12 ) ; do
  if [[ ! -f $container_dir/$package.sif ]]; then
    singularity build \
      --remote \
      $container_dir/$package.sif \
      envs/$package.def 
  fi ;
done

renv

Install all required packages (using r-base in Singularity container).

container_dir=../sing_conts
baseR=r-base_4.0.4

bsub -Is "singularity shell $container_dir/$baseR"
# Install all required packages
renv::restore()

Copy scripts from Simon Martin’s GitHub repo

wget -P code/scripts/introgression https://raw.githubusercontent.com/simonhmartin/genomics_general/master/ABBABABAwindows.py

wget -P code/scripts/introgression https://raw.githubusercontent.com/simonhmartin/genomics_general/master/genomics.py

Process multiple alignment data

Download from Ensembl

  • Ensembl 103: Only includes Oryzias latipes HdrR and Oryzias melastigma (Indian medaka).
  • Ensembl 102: Includes all target species. Use.

ftp://ftp.ensembl.org/pub/release-102/emf/ensembl-compara/multiple_alignments/50_fish.epo/README.50_fish.epo reads:

Alignments are grouped by japanese medaka hdrr chromosome, and then by coordinate system. Alignments containing duplications in japanese medaka hdrr are dumped once per duplicated segment. The files named .other.emf contain alignments that do not include any japanese medaka hdrr region. Each file contains up to 200 alignments.

ftp_dir=ftp://ftp.ensembl.org/pub/release-102/emf/ensembl-compara/multiple_alignments/50_fish.epo/
target_dir=../introgression/release-102

mkdir -p $target_dir/raw

# download, exlcuding *.other* files
wget -P $target_dir/raw $ftp_dir/* -R "*other*"

# unzip into new directory (excluding "other")
$target_dir/unzipped
mkdir -p $target_dir/unzipped

for i in $(find $target_dir/raw/50_fish.epo.[0-9]*); do
  name=$(basename $i | cut -f3,4 -d'.');
  bsub "zcat $i > $target_dir/unzipped/$name";
done
  • NOTE: File 6_2.emf is in a completely different format, with CIGAR strings instead of the normal SEQ, TREE, ID and DATA segments. It appears the file is corrupted.
  • The 6_2 file in release 101 is unaffected. Remove all release 102 chr 6 files and replace with release 101 files.
# remove release 102 files for chr 6
rm $target_dir/unzipped/6_*

# download chr 6 files from release 101
ftp_dir_101=ftp://ftp.ensembl.org/pub/release-101/emf/ensembl-compara/multiple_alignments/50_fish.epo/
target_dir_101=../introgression/release-101

mkdir -p $target_dir_101/raw

wget -P $target_dir_101/raw $ftp_dir_101/50_fish.epo.6_*

# unzip
mkdir -p $target_dir_101/unzipped

for i in $(find $target_dir_101/raw/*); do
  name=$(basename $i | cut -f3,4 -d'.') ;
  zcat $i > $target_dir_101/unzipped/$name ;
done

# copy over to release 102 directory
cp $target_dir_101/unzipped/* $target_dir/unzipped

Generate tree plot

Copy tree to file

tree_file=data/introgression/release_102_tree.txt

awk "NR==58,NR==205" $target_dir/raw/README.50_fish.epo \
  > $tree_file

Then manually edit $tree_file using regex to find spaces and replace them with "_": {bash} (?<=[a-z])( )(?=[a-z])

phylo_tree <- ape::read.tree(file = here::here("data", "introgression", "release_102_tree.txt"))

Full tree

# Colour all Oryzias
ids <- phylo_tree$tip.label[grep("Oryzias_latipes", phylo_tree$tip.label)]
# get indices of edges descending from MRCA (determined through trial and error)
oryzias_nodes <- seq(39, 42)
all_med_col <- ifelse(1:length(phylo_tree[["edge.length"]]) %in% oryzias_nodes, "#E84141", "black")
# set colours for tip labels
all_med_tip <- ifelse(phylo_tree$tip.label %in% ids, "#E84141", "black")
# plot
ape::plot.phylo(phylo_tree,
                use.edge.length = T,
                edge.color = all_med_col,
                tip.color = all_med_tip,
                font = 4)

# Save to repo
png(file= file.path(plots_dir, "tree_all_olat_highlight.png"),
    width=22,
    height=25,
    units = "cm",
    res = 400)
ape::plot.phylo(phylo_tree,
                use.edge.length = T,
                edge.color = all_med_col,
                tip.color = all_med_tip,
                font = 4)
dev.off()

Oryzias only

New tree file created manually to extract Oryzias fishes only, and replace reference codes (e.g. “ASM223467v1”) with line names (e.g. “HdrR”).

in_file = here::here("data/introgression/release_102_tree_oryzias_only.txt")
# Read in
phylo_tree <- ape::read.tree(file = in_file)
# Set colours 
phylo_cols <- c("#55b6b0", "#f33a56", "#f3b61f", "#f6673a", "#631e68")
# Plot
ape::plot.phylo(phylo_tree,
                font = 4,
                tip.color = phylo_cols)

out_file = here::here(plots_dir, "tree_oryzias.png")
# Save
png(file=out_file,
    width=2700,
    height=1720,
    units = "px",
    res = 400)
ape::plot.phylo(phylo_tree,
                font = 4,
                tip.color = phylo_cols)
dev.off()

Add cross for ancestor

out_file = here::here(plots_dir, "tree_oryzias_with_ancestor.png")
in_file = here::here(plots_dir, "tree_oryzias.png")

tree_path = in_file

ggdraw() +
  draw_image(tree_path) +
  draw_label("x",
             x = 0.152,
             y = 0.52,
             fontface = "bold",
             color = "#f77cb5",
             size = 25)

ggsave(out_file,
    width=15.69,
    height=10,
    units = "cm",
    dpi = 400)
knitr::include_graphics(basename(out_file))

Oryzias latipes only

New tree file created manually to extract Oryzias latipes fishes only, and replace reference codes (e.g. “ASM223467v1”) with line names (e.g. “HdrR”).

in_file = here::here("data/introgression/release_102_tree_oryzias_latipes_only.txt")
# Read in
phylo_tree <- ape::read.tree(file = in_file)
# Set colours 
phylo_cols <- c("#9E2B25", "#f6673a", "#631e68")
# Plot
ape::plot.phylo(phylo_tree,
                font = 4,
                tip.color = phylo_cols)

out_file = here::here(plots_dir, "tree_oryzias_latipes.png")
# Save
png(file=out_file,
    width=2700,
    height=1720,
    units = "px",
    res = 400)
ape::plot.phylo(phylo_tree,
                font = 4,
                tip.color = phylo_cols)
dev.off()

Add cross for ancestor

out_file = here::here(plots_dir, "tree_oryzias_latipes_with_ancestor.png")
in_file = here::here(plots_dir, "tree_oryzias_latipes.png")

tree_path = in_file

ggdraw() +
  draw_image(tree_path) +
  draw_label("x",
             x = 0.152,
             y = 0.52,
             fontface = "bold",
             color = "#f77cb5",
             size = 25)

ggsave(out_file,
    width=15.69,
    height=10,
    units = "cm",
    dpi = 400)
knitr::include_graphics(basename(out_file))

Divide by segment

target_dir=../introgression/release-102
segments_dir=$target_dir/segmented
date=20210312
script=code/scripts/introgression/20200907_extract-emf-segments.sh

mkdir -p $segments_dir

for i in $(find $target_dir/unzipped/* ); do
  # get basename
  bname=$(basename $i);
  bname_short=$(echo ${bname::-4} );
  # get chromosome
  chr=$(echo $bname | cut -f1 -d"_" );
  # make directory for each EMF file
  new_path=$(echo $segments_dir/$bname_short );
  if [ ! -d "$new_path" ]; then
    mkdir $new_path;
  fi
  # get segment count
  segment_count=$(grep "^DATA" $i | wc -l );
  # get segment start and end for each file
  for j in $(seq 1 $segment_count ); do
    bsub \
      -o ../log/$date\segment_$bname_short\_$j.out \
      -e ../log/$date\segment_$bname_short\_$j.err \
      "$script $i $j $new_path "
  done;  
done

# How many files?
find $segments_dir/*/*.data.txt | wc -l
# 8951
find $in_dir/*/*_1.data.txt | wc -l
# 4341
find $in_dir/*/*_-1.data.txt | wc -l
# 4610

Run analysis pipeline with snakemake

snmk_proj="introgression"

module load singularity
conda activate snakemake

snakemake \
 --jobs 5000 \
 --latency-wait 100 \
 --cluster-config code/snakemake/$snmk_proj/config/cluster.json \
 --cluster 'bsub -g /snakemake_bgenie -J {cluster.name} -n {cluster.n} -M {cluster.memory} -o {cluster.output} -e {cluster.error}' \
 --keep-going \
 --rerun-incomplete \
 --use-conda \
 --use-singularity \
 -s code/snakemake/$snmk_proj/Snakefile \
 -p

f statistic analysis

Read in data

data_file = here::here("data", "introgression", "20210315_f_stat_final.txt")
# Read in data
final_df <- read.table(data_file,
                       header = T,
                       sep = "\t",
                       as.is = T)

final_df <- final_df %>% 
  dplyr::mutate(across(P2,
                       ~factor(.x, levels = fish_order))) %>% 
  dplyr::mutate(chr = factor(chr, levels = chr_order))

knitr::kable(head(final_df))
P1 P2 P3 chr d_stat z_score admix_f f_ci_lower f_ci_upper
javanicus HdrR MIKK all 0.9072306 324.06735 0.7093524 0.6943606 0.7243441
javanicus HdrR MIKK 1 0.9422313 162.46960 0.8090713 0.7776743 0.8404682
javanicus HdrR MIKK 2 0.9128441 57.55129 0.7668972 0.6931469 0.8406474
javanicus HdrR MIKK 3 0.8869725 76.53532 0.6217246 0.5501172 0.6933320
javanicus HdrR MIKK 4 0.9318431 72.86056 0.7503846 0.6643958 0.8363734
javanicus HdrR MIKK 5 0.8879805 69.67407 0.6565419 0.5865893 0.7264945

Create DF with mean melastigma and javanicus

cor_df <- final_df %>% 
  # filter for when P1 is another Oryzias, and P2 
  dplyr::filter(P1 %in% c("javanicus", "melastigma") & P2 != "MIKK" & P3 == "MIKK") %>% 
  # pivot to put the admixture_f stat for melastigma and javanicus in the same row
  tidyr::pivot_wider(id_cols = c("P2", "chr"),
                     names_from = P1,
                     values_from = c(admix_f, f_ci_lower, f_ci_upper))

cor_df$chr <- as.character(cor_df$chr)
cor_df$chr <- ifelse(cor_df$chr == "all", "genome-wide", cor_df$chr)
chr_order_plot <- c(seq(1,24), "genome-wide")
cor_df$chr <- factor(cor_df$chr, levels = chr_order_plot)

cor_df_means <- cor_df %>%
  # apply across rows
  dplyr::rowwise() %>% 
  # get means for f and CIs
  dplyr::mutate(mean_f = mean(c(admix_f_javanicus, admix_f_melastigma)),
                mean_ci_upper = mean(c(f_ci_upper_javanicus, f_ci_upper_melastigma)),
                mean_ci_lower = mean(c(f_ci_lower_javanicus, f_ci_lower_melastigma))) %>% 
  # set stats at a maximum of 1
  dplyr::mutate(across(c("mean_f", "mean_ci_upper", "mean_ci_lower"),
                       ~dplyr::if_else(.x > 1,
                                       1,
                                       .x)))

knitr::kable(head(cor_df_means))
P2 chr admix_f_javanicus admix_f_melastigma f_ci_lower_javanicus f_ci_lower_melastigma f_ci_upper_javanicus f_ci_upper_melastigma mean_f mean_ci_upper mean_ci_lower
HdrR genome-wide 0.7093524 0.6860648 0.6943606 0.6712495 0.7243441 0.7008800 0.6977086 0.7126121 0.6828051
HdrR 1 0.8090713 0.7831495 0.7776743 0.7466954 0.8404682 0.8196036 0.7961104 0.8300359 0.7621849
HdrR 2 0.7668972 0.7621796 0.6931469 0.6999464 0.8406474 0.8244128 0.7645384 0.8325301 0.6965466
HdrR 3 0.6217246 0.5968322 0.5501172 0.5217981 0.6933320 0.6718664 0.6092784 0.6825992 0.5359576
HdrR 4 0.7503846 0.7399951 0.6643958 0.6811117 0.8363734 0.7988785 0.7451899 0.8176260 0.6727538
HdrR 5 0.6565419 0.6241430 0.5865893 0.5565435 0.7264945 0.6917426 0.6403425 0.7091186 0.5715664

Plot

fstat_plot = cor_df_means %>% 
  ggplot(aes(P2, mean_f, fill = P2)) +
    geom_col() +
    geom_errorbar(aes(ymin = mean_ci_lower,
                      ymax = mean_ci_upper),
                  position = position_dodge(0.9),
                  width = 0.25) +  
    guides(fill = F) +
    facet_wrap(~chr) +
    ylim(0,1) +
    ylab(expression(paste("Mean ", italic("f"), " statistic"))) +
    theme_cowplot(font_size = 8) +
    scale_fill_manual(values = pal_abba)

fstat_plot

out_file = here::here(plots_dir, "20210315_f_stat")

# PNG
ggsave(filename = paste(out_file, ".png", sep = ""),
       device = "png",
       width = 24.75,
       height = 19.5,
       units = "cm",
       dpi = 500)

# SVG
ggsave(filename = paste(out_file, ".svg", sep = ""),
       device = "svg",
       width = 24.75,
       height = 19.5,
       units = "cm")

Sliding windows ABBA BABA

Read in data

in_file = here::here("data", "introgression", "abba_sliding_final", "50000_100.txt")
# Read in data
df = readr::read_csv(in_file) %>% 
  dplyr::arrange(p1, p2, scaffold, start)

# Convert fd to 0 if D < 0
df$fd = ifelse(df$D < 0,
               0,
               df$fd)

# Change names
df = df %>% 
  dplyr::mutate(p2 = recode(df$p2, hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))

Plot

Standard

df %>% 
  dplyr::filter(p1 == "melastigma") %>% 
  ggplot() +
    geom_line(aes(mid, fd, colour = p2)) +
    facet_wrap(~scaffold, nrow = 24, ncol = 1) +
    scale_colour_manual(values = pal_abba) +
    theme_bw(base_size = 10) +
    scale_x_continuous(breaks = c(0, 5000000, 10000000, 15000000, 20000000, 25000000, 30000000, 35000000),
                       labels = scales::comma) +
    xlab("Base position") +
    ylab(bquote(italic(f[d]))) +
    labs(colour = "P2")

out_file = here::here(plots_dir, "20210317_abba_sliding.png")

ggsave(filename = out_file,
       device = "png",
       width = 24.75,
       height = 50,
       units = "cm",
       dpi = 300)

Karyoplot

Make custom chromosome scaffold

# Get chromosome lengths
med_chr_lens = read.table(here("data", "Oryzias_latipes.ASM223467v1.dna.toplevel.fa_chr_counts.txt"),
                          col.names = c("chr", "end"))
# Add start
med_chr_lens$start = 1
# Reorder
med_chr_lens = med_chr_lens %>% 
  dplyr::select(chr, start, end)
# Create custom genome
med_genome = regioneR::toGRanges(med_chr_lens)

Process ABBA sliding windows data

in_file = here::here("data", "introgression", "abba_sliding_final", "50000_100.txt")
# Read in data
df = readr::read_csv(in_file) %>% 
  dplyr::arrange(p1, p2, scaffold, start)

# Convert fd to 0 if D < 0
df$fd = ifelse(df$D < 0,
               0,
               df$fd)

# Change names
df = df %>% 
  dplyr::mutate(p2 = recode(df$p2, hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))

# Get df with mean of melastigma/javanicus
df_kp = df %>% 
  pivot_wider(id_cols = c(scaffold, start, end, mid, p2), names_from = p1, values_from = fd) %>%
  # get mean of melastigma/javanicus
  dplyr::mutate(mean_fd = rowMeans(dplyr::select(., melastigma, javanicus), na.rm = T)) %>% 
  dplyr::arrange(p2, scaffold, start)

knitr::kable(head(df_kp))
scaffold start end mid p2 javanicus melastigma mean_fd
1 650001 700000 666130 HdrR NA 0.1231 0.12310
1 700001 750000 721651 HdrR NA 0.2357 0.23570
1 750001 800000 774678 HdrR NA 0.1636 0.16360
1 950001 1000000 974734 HdrR NA 0.2203 0.22030
1 1000001 1050000 1028780 HdrR NA 0.2935 0.29350
1 1050001 1100000 1075868 HdrR 0.4066 0.2985 0.35255

Read in SNP density data

HNI and HSOK
in_file = here::here("data/introgression/hni_hsok.txt.gz")
# Read in file on local
ol_ranges_df = read.table(in_file,
                          header = T, 
                          sep = "\t", 
                          as.is = T)

ol_ranges_df_long = ol_ranges_df %>% 
  tidyr::pivot_longer(cols = c(hni, hsok), names_to = "line", values_to = "present")

ol_ranges_list = split(ol_ranges_df_long, f = ol_ranges_df_long$line)

ol_ranges_list = lapply(ol_ranges_list, function(x){
  # remove NAs
  df = x %>% 
    tidyr::drop_na(present)
  # convert to GRanges object
  ol_ranges = GenomicRanges::makeGRangesFromDataFrame(df,
                                                      ignore.strand = T,
                                                      seqnames.field = "chr",
                                                      start.field = "pos",
                                                      end.field = "pos")
  return(ol_ranges)
})
MIKK
in_file = here::here("data/introgression/mikk.txt.gz")
# Read in file on local
mikk_ranges_df = read.table(in_file,
                            col.names = c("chr", "pos"), 
                            sep = "\t", 
                            as.is = T)

# Convert to GRanges object

mikk_ranges = GenomicRanges::makeGRangesFromDataFrame(mikk_ranges_df,
                                                      ignore.strand = T,
                                                      seqnames.field = "chr",
                                                      start.field = "pos",
                                                      end.field = "pos")

Get exon density

# Get list of exons from biomaRt

## Select dataset
olat_mart = biomaRt::useEnsembl(biomart = "ensembl", dataset = "olatipes_gene_ensembl")
## Get attributes of interest (exon ID, chr, start, end)
exons <- biomaRt::getBM(attributes = c("chromosome_name", "ensembl_gene_id", "ensembl_transcript_id", "transcript_start", "transcript_end", "transcript_length", "ensembl_exon_id", "rank", "strand", "exon_chrom_start", "exon_chrom_end", "cds_start", "cds_end"),
               mart = olat_mart)
## Convert exons to GRanges
ex_ranges = GenomicRanges::makeGRangesFromDataFrame(exons,
                                                    ignore.strand = T,
                                                    seqnames.field = "chromosome_name",
                                                    start.field = "exon_chrom_start",
                                                    end.field = "exon_chrom_end")

All chromosomes

file_out = file.path(plots_dir, "20210318_fd_with_density_all.png")
# Save
png(file=file_out,
    width=8500,
    height=13500,
    units = "px",
    res = 400)
# Plot 
kp = plotKaryotype(med_genome)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.3)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.4)
# Add fd data
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.4)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.4)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.4)
#kpAddLabels(kp, labels="HdrR",
#            r0=0.45, r1=0.6, 
#            cex = 0.4)
kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 0.6)
dev.off()
knitr::include_graphics(basename(file_out))

Chromosome 4

out_file = file.path(plots_dir, "20210318_fd_with_density_chr_4.png")
png(file=out_file,
    width=5500,
    height=1186,
    units = "px",
    res = 400)

# Plot 
kp = plotKaryotype(med_genome, chromosomes = "4", cex = 1.5)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.7)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.8)
# Add fd data
lwd = 2
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.5)
#kpAddLabels(kp, labels="HdrR",
#            r0=0.45, r1=0.6, 
#            cex = 0.4)
kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 1)
dev.off()
knitr::include_graphics(basename(out_file))

Final figure

ABBA BABA diagram

Created with Vectr and saved here: plots/introgression/20210318_abba_diagram.svg

Compile all

abba_diagram = here::here(plots_dir, "abba_diagram.png")
tree = here::here(plots_dir, "tree_oryzias_with_ancestor.png")
karyo_chr4 = here::here(plots_dir, "20210318_fd_with_density_chr_4.png")

final_abba = ggdraw() +
  draw_image(tree,
            x = 0, y = .7, width = .4, height = .35, vjust = .1, hjust = -.1, scale = 1.2) +
  draw_image(karyo_chr4,
             x = 0, y = 0, width = 1, height = 0.3, scale = 1.2) +   
  draw_plot(fstat_plot,
             x = .4, y = .3, width = .6, height = .7) +
  draw_image(abba_diagram,
          x = 0, y = .3, width = .4, height = .35, vjust = -.05, scale = 1.1) +
  draw_plot_label(label = c("A", "B", "C", "D"), size = 16,
                  x = c(0, 0, .38, 0), y = c(1, .7, 1, .3))  


final_abba

NA
NA
ggsave(here::here(plots_dir, "20210318_final_figure.png"),
       width = 35,
       height = 21.875,
       units = "cm",
       dpi = 500)

New final figure with circos

Circos

Read in data

target_file = here::here("data/introgression/abba_sliding_final_with_icab/min-sites-250.txt")

Sanity check with counts of sites:

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  dplyr::count(p1, p2)

── Column specification ────────────────────────────────────────────────────────────────────────────────────────
cols(
  scaffold = col_double(),
  start = col_double(),
  end = col_double(),
  mid = col_double(),
  sites = col_double(),
  sitesUsed = col_double(),
  ABBA = col_double(),
  BABA = col_double(),
  D = col_double(),
  fd = col_double(),
  fdM = col_double(),
  p1 = col_character(),
  p2 = col_character()
)

As suggested by Simon Martin here: https://github.com/simonhmartin/genomics_general#abba-baba-statistics-in-sliding-windows > fd gives meaningless values (<0 or >1) if D is negative. If there is no excess of shared derived alleles between P2 and P3 (indicated by a positive D), then the excess cannot be quantified. fd values for windows with negative D should therefore either be discarded or converted to zero, depending on your hypothesis.

How many windows have D > 0?

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode lines
  dplyr::mutate(across(c("p1", "p2"), ~factor(.x, levels = c("icab", "hdrr", "hni", "hsok"))),
                across(c("p1", "p2"), ~recode(.x, icab = "iCab", hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))) %>% 
  dplyr::group_by(p1, p2) %>% 
  dplyr::summarise(n_pos_d = length(which(D > 0))) %>% 
  ggplot() +
    geom_col(aes(p2, n_pos_d, fill = p2)) +
    facet_wrap(~p1) +
    scale_fill_manual(values = pal_abba) +
    xlab("P2") +
    ylab("Number of windows (sites) with positive D") +
    ggtitle("Choice of P1 (iCab or HdrR)") +
    theme_cowplot() +
    labs(fill = "P2")

ggsave(here::here("plots/introgression/20210429_p1_hdrr_v_icab_counts_valid_sites.png"),
       device = "png",
       width=15.69,
       height=10,
       units = "cm",
       dpi = 400)

Distributions of \(f_D\)

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode lines
  dplyr::mutate(across(c("p1", "p2"), ~factor(.x, levels = c("icab", "hdrr", "hni", "hsok"))),
                across(c("p1", "p2"), ~recode(.x, icab = "iCab", hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))) %>%
  # remove all rows where D < 0
  dplyr::filter(D > 0) %>% 
  ggplot() +
    geom_histogram(aes(fd, fill = p2), bins = 50) +
    facet_wrap(vars(p1, p2)) +
    scale_fill_manual(values = pal_abba) +
    xlab("P2") +
#    ylab("Number of windows (sites) with positive D") +
    ggtitle(expression(italic(f[d]))) +
    theme_cowplot()  

ggsave(here::here("plots/introgression/20210429_p1_hdrr_v_icab_fd_distribution.png"),
       device = "png",
       width=15.69,
       height=10,
       units = "cm",
       dpi = 400)

Get mean fd for each population

readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode lines
  dplyr::mutate(across(c("p1", "p2"), ~factor(.x, levels = c("icab", "hdrr", "hni", "hsok"))),
                across(c("p1", "p2"), ~recode(.x, icab = "iCab", hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))) %>%
  # remove all rows where D < 0
  dplyr::filter(D > 0) %>% 
  dplyr::filter(p1 == "HdrR") %>% 
  dplyr::group_by(p2) %>% 
  dplyr::summarise(mean(fd))
mikk_abba_final = readr::read_csv(target_file) %>% 
  # add sliding window length
  dplyr::mutate(window_length_kb = (end - start + 1) / 1000) %>% 
  # filter for 500 kb windows
  dplyr::filter(window_length_kb == 500) %>% 
  # recode `fd` as 0 if `D` is negative
  dplyr::mutate(fd = ifelse(D < 0, 0, fd))

# Is iCab or HdrR closer to MIKK?
mikk_abba_final %>% 
  dplyr::filter(p2 %in% c("icab", "hdrr")) %>% 
  dplyr::group_by(p1, p2) %>% 
  dplyr::summarise(length(which(fd == 0)))
NA
NA

There are fewer 0s when HdrR is P1, which suggests that iCab is more closely related to the MIKK panel. But you want a P1 that is further away so that you’ll get more data points, which is why we’ll likely go with HdrR.

mikk_abba_final = mikk_abba_final %>% 
  # recode lines
  dplyr::mutate(p2 = factor(p2, levels = c("hdrr", "icab", "hni", "hsok")),
                p2 = recode(p2, hdrr = "HdrR", icab = "iCab", hni = "HNI", hsok = "HSOK")) %>% 
  dplyr::arrange(p2, scaffold, start) %>% 
  dplyr::select(scaffold, mid_1 = mid, mid_2 = mid, fd, p1, p2) %>% 
  dplyr::mutate(scaffold = paste("chr", scaffold, sep ="")) %>% 
  split(., f = .$p1) %>% 
  purrr::map(., function(P1) split(P1, f = P1$p2)) %>% 
  # Remove empty data frames for hdrr-hdrr and icab-icab population combinations
  purrr::map(., function(P1) P1[purrr::map_lgl(P1, function(P2) nrow(P2) != 0)])

Plot

out_plot = here::here("plots", "introgression", "20210427_introgression_circos_MIKK_ABBA_p1-hdrr.png")
target_list = mikk_abba_final[["hdrr"]]

png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 500)

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 6))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

# Print label in center
text(0, 0, "MIKK panel\nintrogression with\niCab, HNI,\nand\nHSOK")

###############
# Introgression
###############
counter = 0

purrr::map(target_list, function(P2){
  # Set counter
  counter <<- counter + 1
  
  circos.genomicTrack(P2,
      panel.fun = function(region, value, ...){
        circos.genomicLines(region,
                            value[[1]],
                            col = pal_abba[[names(target_list[counter])]],
                            area = T,
                            border = karyoploteR::darker(pal_abba[[names(target_list[counter])]],
                                                         amount = 80))
        # Add baseline
        circos.xaxis(h = "bottom",
                     labels = F,
                     major.tick = F)
      },
      track.height = 0.1,
      bg.border = NA,
      ylim = c(0, 1))
  
  # Add axis for introgression
  circos.yaxis(side = "right",
             at = c(.5, 1),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  
  # Add y-axis label for introgression
  if (counter == 2) {
  circos.text(0, 0.5,
              labels = expression(italic(f[d])),
              sector.index = "chr1",
#              facing = "clockwise",
              adj = c(3, 0.5),
              cex = 0.4*par("cex"))
  }
  
  # Add y-axis label for introgression
  circos.text(0, 0.5,
              labels = names(target_list)[counter],
              sector.index = "chr1",
              facing = "clockwise",
              adj = c(.5, 0),
              cex = 0.6*par("cex"))  
})

circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

out_plot = here::here("plots", "introgression", "20210427_introgression_circos_MIKK_ABBA_p1-icab.png")
target_list = mikk_abba_final[["icab"]]

png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 500)

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 6))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

# Print label in center
text(0, 0, "MIKK panel\nintrogression with\nHdrR, HNI,\nand\nHSOK")

###############
# Introgression
###############
counter = 0

purrr::map(target_list, function(P2){
  # Set counter
  counter <<- counter + 1
  
  circos.genomicTrack(P2,
      panel.fun = function(region, value, ...){
        circos.genomicLines(region,
                            value[[1]],
                            col = pal_abba[[names(target_list[counter])]],
                            area = T,
                            border = karyoploteR::darker(pal_abba[[names(target_list[counter])]]))
        # Add baseline
        circos.xaxis(h = "bottom",
                     labels = F,
                     major.tick = F)
      },
      track.height = 0.1,
      bg.border = NA,
      ylim = c(0, 1))
  
  # Add axis for introgression
  circos.yaxis(side = "right",
             at = c(.5, 1),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  
  # Add y-axis label for introgression
  if (counter == 2) {
  circos.text(0, 0.5,
              labels = expression(italic(f[d])),
              sector.index = "chr1",
#              facing = "clockwise",
              adj = c(3, 0.5),
              cex = 0.4*par("cex"))
  }
  
  # Add y-axis label for introgression
  circos.text(0, 0.5,
              labels = names(target_list)[counter],
              sector.index = "chr1",
              facing = "clockwise",
              adj = c(.5, 0),
              cex = 0.6*par("cex"))  
})

circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

Final for paper (with iCab as yellow)

out_plot = here::here("plots", "introgression", "20210505_introgression_circos_MIKK_ABBA_p1-hdrr.png")
target_list = mikk_abba_final[["hdrr"]]

# Reset palette
pal_abba <- c("#F3B61F", "#F3B61F", "#631E68", "#F6673A", "#F33A56", "#55B6B0", "#621B00")
names(pal_abba) <- c("iCab", "HdrR", "HSOK", "HNI", "melastigma", "javanicus", "Kaga")

png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 500)

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 6))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

# Print label in center
text(0, 0, "MIKK panel\nintrogression with\niCab, HNI,\nand\nHSOK")

###############
# Introgression
###############
counter = 0

purrr::map(target_list, function(P2){
  # Set counter
  counter <<- counter + 1
  
  circos.genomicTrack(P2,
      panel.fun = function(region, value, ...){
        circos.genomicLines(region,
                            value[[1]],
                            col = pal_abba[[names(target_list[counter])]],
                            area = T,
                            border = karyoploteR::darker(pal_abba[[names(target_list[counter])]],
                                                         amount = 80))
        # Add baseline
        circos.xaxis(h = "bottom",
                     labels = F,
                     major.tick = F)
      },
      track.height = 0.1,
      bg.border = NA,
      ylim = c(0, 1))
  
  # Add axis for introgression
  circos.yaxis(side = "right",
             at = c(.5, 1),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  
  # Add y-axis label for introgression
  if (counter == 2) {
  circos.text(0, 0.5,
              labels = expression(italic(f[d])),
              sector.index = "chr1",
#              facing = "clockwise",
              adj = c(3, 0.5),
              cex = 0.4*par("cex"))
  }
  
  # Add y-axis label for introgression
  circos.text(0, 0.5,
              labels = names(target_list)[counter],
              sector.index = "chr1",
              facing = "clockwise",
              adj = c(.5, 0),
              cex = 0.6*par("cex"))  
})

circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

Re-do final figure (just tree, schema, and circos)

abba_diagram = here::here(plots_dir, "20210505_abba_diagram.png")
tree = here::here(plots_dir, "tree_oryzias_latipes_with_ancestor.png")
circos_abba = here::here(plots_dir, "20210505_introgression_circos_MIKK_ABBA_p1-hdrr.png")

final_abba = ggdraw() +
  draw_image(tree,
            x = 0, y = .5, width = .4, height = .55, vjust = 0, hjust = -.1, scale = 1.2) +    
  draw_image(circos_abba,
             x = .4, y = 0, width = .6, height = 1, scale = 1.1, vjust = 0) +
  draw_image(abba_diagram,
          x = 0, y = 0, width = .4, height = .55, vjust = 0, hjust = -.125, scale = 1.2) +
  draw_plot_label(label = c("A", "B", "C"), size = 25,
                  x = c(0, 0, .4), y = c(1, .6, 1), color = "#4f0943")  


final_abba

ggsave(here::here(plots_dir, "20210505_introgression_final_figure.png"),
       width = 35,
       height = 21.875,
       units = "cm",
       dpi = 500)

Re-do final figure

Chr2

Read in new data

in_file = here::here("data/introgression/abba_sliding_final_no_131-1", "500000_250.txt")
# Read in data
df = readr::read_csv(in_file) %>% 
  dplyr::arrange(p1, p2, scaffold, start)

# Convert fd to 0 if D < 0
df$fd = ifelse(df$D < 0,
               0,
               df$fd)

# Change names
df = df %>% 
  dplyr::mutate(p2 = recode(df$p2, hdrr = "HdrR", hni = "HNI", hsok = "HSOK"))

# Get df with mean of melastigma/javanicus
df_kp = df %>% 
  pivot_wider(id_cols = c(scaffold, start, end, mid, p2), names_from = p1, values_from = fd) %>%
  # get mean of melastigma/javanicus
  dplyr::mutate(mean_fd = rowMeans(dplyr::select(., melastigma, javanicus), na.rm = T)) %>% 
  dplyr::arrange(p2, scaffold, start)

knitr::kable(head(df_kp))
scaffold start end mid p2 javanicus melastigma mean_fd
1 500001 1000000 770583 HdrR NA 0.1788 0.17880
1 1000001 1500000 1227968 HdrR 0.4058 0.2320 0.31890
1 1500001 2000000 1764457 HdrR 0.3459 0.2768 0.31135
1 2000001 2500000 2205406 HdrR NA 0.3024 0.30240
1 2500001 3000000 2776011 HdrR NA 0.3551 0.35510
1 3000001 3500000 3243647 HdrR 0.3074 0.2239 0.26565

Plot

chr4
out_file = file.path(plots_dir, "20210409_fd_with_density_chr_4_500kb-window.png")
png(file=out_file,
    width=5500,
    height=1186,
    units = "px",
    res = 400)

# Plot 
kp = plotKaryotype(med_genome, chromosomes = "4", cex = 1.5)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.7)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.8)
# Add fd data
lwd = 2
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.5)

kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 1)
dev.off()
knitr::include_graphics(basename(out_file))

chr2
out_file = file.path(plots_dir, "20210409_fd_with_density_chr_2_500kb-window.png")
png(file=out_file,
    width=5500,
    height=1186,
    units = "px",
    res = 400)

# Plot 
kp = plotKaryotype(med_genome, chromosomes = "2", cex = 1.5)
# Add base numbers 
karyoploteR::kpAddBaseNumbers(kp, tick.dist = 5000000, cex = 0.7)
# Add data backgrounds
karyoploteR::kpDataBackground(kp, r0=0, r1 = 1, color = "white")
# Add axis label
kpAxis(kp, r0=0.3, r1 = 1, cex = 0.8)
# Add fd data
lwd = 2
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HNI"],
                     x = df_kp$mid[df_kp$p2 == "HNI"],
                     y = df_kp$mean_fd[df_kp$p2 == "HNI"],
                     col = "#F6673A",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HdrR"],
                     x = df_kp$mid[df_kp$p2 == "HdrR"],
                     y = df_kp$mean_fd[df_kp$p2 == "HdrR"],
                     col = "#F3B61F",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
karyoploteR::kpLines(kp,
                     chr = df_kp$scaffold[df_kp$p2 == "HSOK"],
                     x = df_kp$mid[df_kp$p2 == "HSOK"],
                     y = df_kp$mean_fd[df_kp$p2 == "HSOK"],
                     col = "#631E68",
                     r0=0.3, r1 = 1,
                     lwd = lwd)
# Add SNP density data
kpPlotDensity(kp, data=mikk_ranges, col = "#49A379",
              r0=0, r1=0.1, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hni, col = "#F6673A",
              r0=0.1, r1=0.2, 
              window.size = 25000)
kpPlotDensity(kp, data=ol_ranges_list$hsok, col = "#631E68", 
              r0=0.2, r1=0.3, 
              window.size = 25000)
#kpPlotDensity(kp, data=ol_ranges_list$hdrr, col = "#F3B61F",
#              r0=0.45, r1=0.6,
#              window.size = 25000)
# Add exon density to ideogram
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 1)
kpPlotDensity(kp, data=ex_ranges, col = "#f77cb5",
              data.panel = "ideogram",
              window.size = 25000,
              r0 = 0.5, r1 = 0)
# Add labels
kpAddLabels(kp, labels="MIKK",
            r0=0, r1=0.05,
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HNI",
            r0=0.1, r1=0.15, 
            label.margin = 0.001,
            cex = 0.5)
kpAddLabels(kp, labels="HSOK",
            r0=0.2, r1=0.25,
            label.margin = 0.001,
            cex = 0.5)

kpAddLabels(kp, labels=bquote(italic(f[d])),
            r0=0.3, r1=1, 
            label.margin = 0.035,
            cex = 1)
dev.off()
knitr::include_graphics(basename(out_file))

Use chr4.

Compose final figure

abba_diagram = here::here(plots_dir, "abba_diagram.png")
tree = here::here(plots_dir, "tree_oryzias_with_ancestor.png")
karyo_chr4 = here::here(plots_dir, "20210409_fd_with_density_chr_4_500kb-window.png")
circos_abba = here::here(plots_dir, "20210409_introgression_circos_MIKK_ABBA.png")

final_abba = ggdraw() +
  draw_image(tree,
            x = 0, y = .7, width = .4, height = .35, vjust = .1, hjust = -.1, scale = 1.2) +
  draw_image(karyo_chr4,
             x = 0, y = 0, width = 1, height = 0.3, scale = 1.2) +  
  draw_image(circos_abba,
             x = .4, y = .3, width = .6, height = .7, scale = 1.15, vjust = .025) +
  draw_image(abba_diagram,
          x = 0, y = .3, width = .4, height = .35, vjust = -.05, scale = 1.1) +
  draw_plot_label(label = c("A", "B", "C", "D"), size = 25,
                  x = c(0, 0, .45, 0), y = c(1, .7, 1, .3), color = "#4f0943")  


final_abba

ggsave(here::here(plots_dir, "20210409_introgression_final_figure.png"),
       width = 35,
       height = 21.875,
       units = "cm",
       dpi = 500)
LS0tCnRpdGxlOiAiSW50cm9ncmVzc2lvbiIKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpKWAnCiNvdXRwdXQ6CiMgIGh0bWxfZG9jdW1lbnQ6CiMgICAgdG9jOiB0cnVlCiMgICAgdG9jX2Zsb2F0OiB0cnVlCiMgICAgZGV2OiAnc3ZnJwojICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQojICAgIHBhbmRvY19hcmdzOiAtLWx1YS1maWx0ZXI9Y29sb3ItdGV4dC5sdWEKIyAgICBoaWdobGlnaHQ6IHB5Z21lbnRzICAKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKV2Ugd2FudCB0byBkZXRlcm1pbmUgdGhlIGV4dGVudCB0byB3aGljaCB0aGUgTUlLSyBwYW5lbCBzaG93cyBldmlkZW5jZSBvZiBpbnRyb2dyZXNzaW9uIHdpdGggb3RoZXIgbWVkYWthIHBvcHVsYXRpb25zLCBzcGVjaWZpY2FsbHkgdGhlIGFsbG9wYXRyaWMgTm9ydGhlcm4gYW5kIEtvcmVhbiBtZWRha2Egc3RyYWlucywgcmVsYXRpdmUgdG8gc3ltcGF0cmljIFNvdXRoZXJuIG1lZGFrYSBzdHJhaW5zLgoKIyBTZXR1cAoKYGBge3IsIG1lc3NhZ2UgPSBGfQpsaWJyYXJ5KGhlcmUpCnNvdXJjZShoZXJlOjpoZXJlKCJjb2RlIiwgInNjcmlwdHMiLCAiaW50cm9ncmVzc2lvbiIsICJzb3VyY2UuUiIpKQpgYGAKCiMjIFdvcmtpbmcgZGlyZWN0b3J5CgpXb3JraW5nIGRpcmVjdG9yeSBvbiBFQkkgY2x1c3RlcjogYC9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9pYW4vbWlra19wYXBlcmAKCiMjIENyZWF0ZSBTaW5ndWxhcml0eSBjb250YWluZXJzCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmNvbnRhaW5lcl9kaXI9Li4vc2luZ19jb250cwojIGxvYWQgU2luZ3VsYXJpdHkgKHZlcnNpb24gMy41LjApCm1vZHVsZSBsb2FkIHNpbmd1bGFyaXR5IAoKZm9yIHBhY2thZ2UgaW4gJCggZWNobyByLWJhc2VfNC4wLjQgYmNmdG9vbHNfMS45IG51bXB5XzEuMTUuNCBiYXNoXzMuMC4yMiBiaW9jb25kdWN0b3JfMy4xMiApIDsgZG8KICBpZiBbWyAhIC1mICRjb250YWluZXJfZGlyLyRwYWNrYWdlLnNpZiBdXTsgdGhlbgogICAgc2luZ3VsYXJpdHkgYnVpbGQgXAogICAgICAtLXJlbW90ZSBcCiAgICAgICRjb250YWluZXJfZGlyLyRwYWNrYWdlLnNpZiBcCiAgICAgIGVudnMvJHBhY2thZ2UuZGVmIAogIGZpIDsKZG9uZQpgYGAKCiMjIGByZW52YAoKSW5zdGFsbCBhbGwgcmVxdWlyZWQgcGFja2FnZXMgKHVzaW5nIHItYmFzZSBpbiBTaW5ndWxhcml0eSBjb250YWluZXIpLgoKYGBge2Jhc2gsIGV2YWwgPSBGfQpjb250YWluZXJfZGlyPS4uL3NpbmdfY29udHMKYmFzZVI9ci1iYXNlXzQuMC40Cgpic3ViIC1JcyAic2luZ3VsYXJpdHkgc2hlbGwgJGNvbnRhaW5lcl9kaXIvJGJhc2VSIgpgYGAKCmBgYHtyLCBldmFsID0gRn0KIyBJbnN0YWxsIGFsbCByZXF1aXJlZCBwYWNrYWdlcwpyZW52OjpyZXN0b3JlKCkKYGBgCgojIyBDb3B5IHNjcmlwdHMgZnJvbSBTaW1vbiBNYXJ0aW4ncyBHaXRIdWIgcmVwbyAKCmBgYHtiYXNoLCBldmFsID0gRn0Kd2dldCAtUCBjb2RlL3NjcmlwdHMvaW50cm9ncmVzc2lvbiBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc2ltb25obWFydGluL2dlbm9taWNzX2dlbmVyYWwvbWFzdGVyL0FCQkFCQUJBd2luZG93cy5weQoKd2dldCAtUCBjb2RlL3NjcmlwdHMvaW50cm9ncmVzc2lvbiBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc2ltb25obWFydGluL2dlbm9taWNzX2dlbmVyYWwvbWFzdGVyL2dlbm9taWNzLnB5CmBgYAoKIyBQcm9jZXNzIG11bHRpcGxlIGFsaWdubWVudCBkYXRhIAoKIyMgRG93bmxvYWQgZnJvbSBFbnNlbWJsCgoqIFtFbnNlbWJsIDEwM117Y29sb3I9InB1cnBsZSJ9OiBPbmx5IGluY2x1ZGVzIE9yeXppYXMgbGF0aXBlcyBIZHJSIGFuZCBPcnl6aWFzIG1lbGFzdGlnbWEgKEluZGlhbiBtZWRha2EpLgoqIFtFbnNlbWJsIDEwMl17Y29sb3I9InB1cnBsZX06IEluY2x1ZGVzIGFsbCB0YXJnZXQgc3BlY2llcy4gVXNlLiAKCmBmdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAyL2VtZi9lbnNlbWJsLWNvbXBhcmEvbXVsdGlwbGVfYWxpZ25tZW50cy81MF9maXNoLmVwby9SRUFETUUuNTBfZmlzaC5lcG9gIHJlYWRzOgoKPkFsaWdubWVudHMgYXJlIGdyb3VwZWQgYnkgamFwYW5lc2UgbWVkYWthIGhkcnIgY2hyb21vc29tZSwgYW5kIHRoZW4gYnkgY29vcmRpbmF0ZSBzeXN0ZW0uCkFsaWdubWVudHMgY29udGFpbmluZyBkdXBsaWNhdGlvbnMgaW4gamFwYW5lc2UgbWVkYWthIGhkcnIgYXJlIGR1bXBlZCBvbmNlIHBlciBkdXBsaWNhdGVkIHNlZ21lbnQuClRoZSBmaWxlcyBuYW1lZCAqLm90aGVyKi5lbWYgY29udGFpbiBhbGlnbm1lbnRzIHRoYXQgZG8gbm90IGluY2x1ZGUgYW55IGphcGFuZXNlIG1lZGFrYSBoZHJyCnJlZ2lvbi4gRWFjaCBmaWxlIGNvbnRhaW5zIHVwIHRvIDIwMCBhbGlnbm1lbnRzLgoKCmBgYHtiYXNoLCBldmFsID0gRn0KZnRwX2Rpcj1mdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAyL2VtZi9lbnNlbWJsLWNvbXBhcmEvbXVsdGlwbGVfYWxpZ25tZW50cy81MF9maXNoLmVwby8KdGFyZ2V0X2Rpcj0uLi9pbnRyb2dyZXNzaW9uL3JlbGVhc2UtMTAyCgpta2RpciAtcCAkdGFyZ2V0X2Rpci9yYXcKCiMgZG93bmxvYWQsIGV4bGN1ZGluZyAqLm90aGVyKiBmaWxlcwp3Z2V0IC1QICR0YXJnZXRfZGlyL3JhdyAkZnRwX2Rpci8qIC1SICIqb3RoZXIqIgoKIyB1bnppcCBpbnRvIG5ldyBkaXJlY3RvcnkgKGV4Y2x1ZGluZyAib3RoZXIiKQokdGFyZ2V0X2Rpci91bnppcHBlZApta2RpciAtcCAkdGFyZ2V0X2Rpci91bnppcHBlZAoKZm9yIGkgaW4gJChmaW5kICR0YXJnZXRfZGlyL3Jhdy81MF9maXNoLmVwby5bMC05XSopOyBkbwogIG5hbWU9JChiYXNlbmFtZSAkaSB8IGN1dCAtZjMsNCAtZCcuJyk7CiAgYnN1YiAiemNhdCAkaSA+ICR0YXJnZXRfZGlyL3VuemlwcGVkLyRuYW1lIjsKZG9uZQpgYGAKCgoqIFsqKk5PVEUqKl17Y29sb3I9InJlZCJ9OiBGaWxlIDZfMi5lbWYgaXMgaW4gYSBjb21wbGV0ZWx5IGRpZmZlcmVudCBmb3JtYXQsIHdpdGggQ0lHQVIgc3RyaW5ncyBpbnN0ZWFkIG9mIHRoZSBub3JtYWwgU0VRLCBUUkVFLCBJRCBhbmQgREFUQSBzZWdtZW50cy4gSXQgYXBwZWFycyB0aGUgZmlsZSBpcyBjb3JydXB0ZWQuIAoqIFRoZSA2XzIgZmlsZSBpbiBgcmVsZWFzZSAxMDFgIGlzIHVuYWZmZWN0ZWQuIFJlbW92ZSBhbGwgYHJlbGVhc2UgMTAyYCBjaHIgNiBmaWxlcyBhbmQgcmVwbGFjZSB3aXRoIGByZWxlYXNlIDEwMWAgZmlsZXMuCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CiMgcmVtb3ZlIHJlbGVhc2UgMTAyIGZpbGVzIGZvciBjaHIgNgpybSAkdGFyZ2V0X2Rpci91bnppcHBlZC82XyoKCiMgZG93bmxvYWQgY2hyIDYgZmlsZXMgZnJvbSByZWxlYXNlIDEwMQpmdHBfZGlyXzEwMT1mdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAxL2VtZi9lbnNlbWJsLWNvbXBhcmEvbXVsdGlwbGVfYWxpZ25tZW50cy81MF9maXNoLmVwby8KdGFyZ2V0X2Rpcl8xMDE9Li4vaW50cm9ncmVzc2lvbi9yZWxlYXNlLTEwMQoKbWtkaXIgLXAgJHRhcmdldF9kaXJfMTAxL3JhdwoKd2dldCAtUCAkdGFyZ2V0X2Rpcl8xMDEvcmF3ICRmdHBfZGlyXzEwMS81MF9maXNoLmVwby42XyoKCiMgdW56aXAKbWtkaXIgLXAgJHRhcmdldF9kaXJfMTAxL3VuemlwcGVkCgpmb3IgaSBpbiAkKGZpbmQgJHRhcmdldF9kaXJfMTAxL3Jhdy8qKTsgZG8KICBuYW1lPSQoYmFzZW5hbWUgJGkgfCBjdXQgLWYzLDQgLWQnLicpIDsKICB6Y2F0ICRpID4gJHRhcmdldF9kaXJfMTAxL3VuemlwcGVkLyRuYW1lIDsKZG9uZQoKIyBjb3B5IG92ZXIgdG8gcmVsZWFzZSAxMDIgZGlyZWN0b3J5CmNwICR0YXJnZXRfZGlyXzEwMS91bnppcHBlZC8qICR0YXJnZXRfZGlyL3VuemlwcGVkCgpgYGAKCiMjIEdlbmVyYXRlIHRyZWUgcGxvdAoKQ29weSB0cmVlIHRvIGZpbGUKCmBgYHtiYXNoLCBldmFsID0gRn0KdHJlZV9maWxlPWRhdGEvaW50cm9ncmVzc2lvbi9yZWxlYXNlXzEwMl90cmVlLnR4dAoKYXdrICJOUj09NTgsTlI9PTIwNSIgJHRhcmdldF9kaXIvcmF3L1JFQURNRS41MF9maXNoLmVwbyBcCiAgPiAkdHJlZV9maWxlCmBgYAoKVGhlbiBtYW51YWxseSBlZGl0IGAkdHJlZV9maWxlYCB1c2luZyByZWdleCB0byBmaW5kIHNwYWNlcyBhbmQgcmVwbGFjZSB0aGVtIHdpdGggIl8iOgpge2Jhc2h9ICg/PD1bYS16XSkoICkoPz1bYS16XSlgCgpgYGB7cn0KcGh5bG9fdHJlZSA8LSBhcGU6OnJlYWQudHJlZShmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbnRyb2dyZXNzaW9uIiwgInJlbGVhc2VfMTAyX3RyZWUudHh0IikpCmBgYAoKIyMjIEZ1bGwgdHJlZSAKCmBgYHtyLCBmaWcud2lkdGg9MTEsIGZpZy5oZWlnaHQ9MTIuNX0KIyBDb2xvdXIgYWxsIE9yeXppYXMKaWRzIDwtIHBoeWxvX3RyZWUkdGlwLmxhYmVsW2dyZXAoIk9yeXppYXNfbGF0aXBlcyIsIHBoeWxvX3RyZWUkdGlwLmxhYmVsKV0KIyBnZXQgaW5kaWNlcyBvZiBlZGdlcyBkZXNjZW5kaW5nIGZyb20gTVJDQSAoZGV0ZXJtaW5lZCB0aHJvdWdoIHRyaWFsIGFuZCBlcnJvcikKb3J5emlhc19ub2RlcyA8LSBzZXEoMzksIDQyKQphbGxfbWVkX2NvbCA8LSBpZmVsc2UoMTpsZW5ndGgocGh5bG9fdHJlZVtbImVkZ2UubGVuZ3RoIl1dKSAlaW4lIG9yeXppYXNfbm9kZXMsICIjRTg0MTQxIiwgImJsYWNrIikKIyBzZXQgY29sb3VycyBmb3IgdGlwIGxhYmVscwphbGxfbWVkX3RpcCA8LSBpZmVsc2UocGh5bG9fdHJlZSR0aXAubGFiZWwgJWluJSBpZHMsICIjRTg0MTQxIiwgImJsYWNrIikKIyBwbG90CmFwZTo6cGxvdC5waHlsbyhwaHlsb190cmVlLAogICAgICAgICAgICAgICAgdXNlLmVkZ2UubGVuZ3RoID0gVCwKICAgICAgICAgICAgICAgIGVkZ2UuY29sb3IgPSBhbGxfbWVkX2NvbCwKICAgICAgICAgICAgICAgIHRpcC5jb2xvciA9IGFsbF9tZWRfdGlwLAogICAgICAgICAgICAgICAgZm9udCA9IDQpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQojIFNhdmUgdG8gcmVwbwpwbmcoZmlsZT0gZmlsZS5wYXRoKHBsb3RzX2RpciwgInRyZWVfYWxsX29sYXRfaGlnaGxpZ2h0LnBuZyIpLAogICAgd2lkdGg9MjIsCiAgICBoZWlnaHQ9MjUsCiAgICB1bml0cyA9ICJjbSIsCiAgICByZXMgPSA0MDApCmFwZTo6cGxvdC5waHlsbyhwaHlsb190cmVlLAogICAgICAgICAgICAgICAgdXNlLmVkZ2UubGVuZ3RoID0gVCwKICAgICAgICAgICAgICAgIGVkZ2UuY29sb3IgPSBhbGxfbWVkX2NvbCwKICAgICAgICAgICAgICAgIHRpcC5jb2xvciA9IGFsbF9tZWRfdGlwLAogICAgICAgICAgICAgICAgZm9udCA9IDQpCmRldi5vZmYoKQpgYGAKCiMjIyBPcnl6aWFzIG9ubHkKCk5ldyB0cmVlIGZpbGUgY3JlYXRlZCBtYW51YWxseSB0byBleHRyYWN0ICpPcnl6aWFzKiBmaXNoZXMgb25seSwgYW5kIHJlcGxhY2UgcmVmZXJlbmNlIGNvZGVzIChlLmcuICJBU00yMjM0Njd2MSIpIHdpdGggbGluZSBuYW1lcyAoZS5nLiAiSGRyUiIpLgoKYGBge3J9CmluX2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vcmVsZWFzZV8xMDJfdHJlZV9vcnl6aWFzX29ubHkudHh0IikKIyBSZWFkIGluCnBoeWxvX3RyZWUgPC0gYXBlOjpyZWFkLnRyZWUoZmlsZSA9IGluX2ZpbGUpCiMgU2V0IGNvbG91cnMgCnBoeWxvX2NvbHMgPC0gYygiIzU1YjZiMCIsICIjZjMzYTU2IiwgIiNmM2I2MWYiLCAiI2Y2NjczYSIsICIjNjMxZTY4IikKIyBQbG90CmFwZTo6cGxvdC5waHlsbyhwaHlsb190cmVlLAogICAgICAgICAgICAgICAgZm9udCA9IDQsCiAgICAgICAgICAgICAgICB0aXAuY29sb3IgPSBwaHlsb19jb2xzKQoKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9Cm91dF9maWxlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXMucG5nIikKIyBTYXZlCnBuZyhmaWxlPW91dF9maWxlLAogICAgd2lkdGg9MjcwMCwKICAgIGhlaWdodD0xNzIwLAogICAgdW5pdHMgPSAicHgiLAogICAgcmVzID0gNDAwKQphcGU6OnBsb3QucGh5bG8ocGh5bG9fdHJlZSwKICAgICAgICAgICAgICAgIGZvbnQgPSA0LAogICAgICAgICAgICAgICAgdGlwLmNvbG9yID0gcGh5bG9fY29scykKZGV2Lm9mZigpCmBgYAoKIyMjIyBBZGQgY3Jvc3MgZm9yIGFuY2VzdG9yCgpgYGB7cn0Kb3V0X2ZpbGUgPSBoZXJlOjpoZXJlKHBsb3RzX2RpciwgInRyZWVfb3J5emlhc193aXRoX2FuY2VzdG9yLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQppbl9maWxlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXMucG5nIikKCnRyZWVfcGF0aCA9IGluX2ZpbGUKCmdnZHJhdygpICsKICBkcmF3X2ltYWdlKHRyZWVfcGF0aCkgKwogIGRyYXdfbGFiZWwoIngiLAogICAgICAgICAgICAgeCA9IDAuMTUyLAogICAgICAgICAgICAgeSA9IDAuNTIsCiAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgIGNvbG9yID0gIiNmNzdjYjUiLAogICAgICAgICAgICAgc2l6ZSA9IDI1KQoKZ2dzYXZlKG91dF9maWxlLAogICAgd2lkdGg9MTUuNjksCiAgICBoZWlnaHQ9MTAsCiAgICB1bml0cyA9ICJjbSIsCiAgICBkcGkgPSA0MDApCmBgYAoKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKG91dF9maWxlKSkKCmlmIChmaWxlLmV4aXN0cyhuZXdfcGF0aCkgIT0gVCl7CiAgZmlsZS5jb3B5KG91dF9maWxlLCBuZXdfcGF0aCkKfQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfZmlsZSkpCmBgYAojIyMgT3J5emlhcyBsYXRpcGVzIG9ubHkKCk5ldyB0cmVlIGZpbGUgY3JlYXRlZCBtYW51YWxseSB0byBleHRyYWN0ICpPcnl6aWFzIGxhdGlwZXMqIGZpc2hlcyBvbmx5LCBhbmQgcmVwbGFjZSByZWZlcmVuY2UgY29kZXMgKGUuZy4gIkFTTTIyMzQ2N3YxIikgd2l0aCBsaW5lIG5hbWVzIChlLmcuICJIZHJSIikuCgoKYGBge3J9CmluX2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vcmVsZWFzZV8xMDJfdHJlZV9vcnl6aWFzX2xhdGlwZXNfb25seS50eHQiKQojIFJlYWQgaW4KcGh5bG9fdHJlZSA8LSBhcGU6OnJlYWQudHJlZShmaWxlID0gaW5fZmlsZSkKIyBTZXQgY29sb3VycyAKcGh5bG9fY29scyA8LSBjKCIjOUUyQjI1IiwgIiNmNjY3M2EiLCAiIzYzMWU2OCIpCiMgUGxvdAphcGU6OnBsb3QucGh5bG8ocGh5bG9fdHJlZSwKICAgICAgICAgICAgICAgIGZvbnQgPSA0LAogICAgICAgICAgICAgICAgdGlwLmNvbG9yID0gcGh5bG9fY29scykKCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpvdXRfZmlsZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAidHJlZV9vcnl6aWFzX2xhdGlwZXMucG5nIikKIyBTYXZlCnBuZyhmaWxlPW91dF9maWxlLAogICAgd2lkdGg9MjcwMCwKICAgIGhlaWdodD0xNzIwLAogICAgdW5pdHMgPSAicHgiLAogICAgcmVzID0gNDAwKQphcGU6OnBsb3QucGh5bG8ocGh5bG9fdHJlZSwKICAgICAgICAgICAgICAgIGZvbnQgPSA0LAogICAgICAgICAgICAgICAgdGlwLmNvbG9yID0gcGh5bG9fY29scykKZGV2Lm9mZigpCmBgYAoKCiMjIyMgQWRkIGNyb3NzIGZvciBhbmNlc3RvcgoKYGBge3J9Cm91dF9maWxlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXNfbGF0aXBlc193aXRoX2FuY2VzdG9yLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQppbl9maWxlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXNfbGF0aXBlcy5wbmciKQoKdHJlZV9wYXRoID0gaW5fZmlsZQoKZ2dkcmF3KCkgKwogIGRyYXdfaW1hZ2UodHJlZV9wYXRoKSArCiAgZHJhd19sYWJlbCgieCIsCiAgICAgICAgICAgICB4ID0gMC4xNTIsCiAgICAgICAgICAgICB5ID0gMC41MiwKICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgY29sb3IgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICBzaXplID0gMjUpCgpnZ3NhdmUob3V0X2ZpbGUsCiAgICB3aWR0aD0xNS42OSwKICAgIGhlaWdodD0xMCwKICAgIHVuaXRzID0gImNtIiwKICAgIGRwaSA9IDQwMCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfZmlsZSkpCgpmaWxlLmNvcHkob3V0X2ZpbGUsIG5ld19wYXRoLCBvdmVyd3JpdGUgPSBUKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfZmlsZSkpCmBgYAoKIyMgRGl2aWRlIGJ5IHNlZ21lbnQKCmBgYHtiYXNoLCBldmFsID0gRn0KdGFyZ2V0X2Rpcj0uLi9pbnRyb2dyZXNzaW9uL3JlbGVhc2UtMTAyCnNlZ21lbnRzX2Rpcj0kdGFyZ2V0X2Rpci9zZWdtZW50ZWQKZGF0ZT0yMDIxMDMxMgpzY3JpcHQ9Y29kZS9zY3JpcHRzL2ludHJvZ3Jlc3Npb24vMjAyMDA5MDdfZXh0cmFjdC1lbWYtc2VnbWVudHMuc2gKCm1rZGlyIC1wICRzZWdtZW50c19kaXIKCmZvciBpIGluICQoZmluZCAkdGFyZ2V0X2Rpci91bnppcHBlZC8qICk7IGRvCiAgIyBnZXQgYmFzZW5hbWUKICBibmFtZT0kKGJhc2VuYW1lICRpKTsKICBibmFtZV9zaG9ydD0kKGVjaG8gJHtibmFtZTo6LTR9ICk7CiAgIyBnZXQgY2hyb21vc29tZQogIGNocj0kKGVjaG8gJGJuYW1lIHwgY3V0IC1mMSAtZCJfIiApOwogICMgbWFrZSBkaXJlY3RvcnkgZm9yIGVhY2ggRU1GIGZpbGUKICBuZXdfcGF0aD0kKGVjaG8gJHNlZ21lbnRzX2Rpci8kYm5hbWVfc2hvcnQgKTsKICBpZiBbICEgLWQgIiRuZXdfcGF0aCIgXTsgdGhlbgogICAgbWtkaXIgJG5ld19wYXRoOwogIGZpCiAgIyBnZXQgc2VnbWVudCBjb3VudAogIHNlZ21lbnRfY291bnQ9JChncmVwICJeREFUQSIgJGkgfCB3YyAtbCApOwogICMgZ2V0IHNlZ21lbnQgc3RhcnQgYW5kIGVuZCBmb3IgZWFjaCBmaWxlCiAgZm9yIGogaW4gJChzZXEgMSAkc2VnbWVudF9jb3VudCApOyBkbwogICAgYnN1YiBcCiAgICAgIC1vIC4uL2xvZy8kZGF0ZVxzZWdtZW50XyRibmFtZV9zaG9ydFxfJGoub3V0IFwKICAgICAgLWUgLi4vbG9nLyRkYXRlXHNlZ21lbnRfJGJuYW1lX3Nob3J0XF8kai5lcnIgXAogICAgICAiJHNjcmlwdCAkaSAkaiAkbmV3X3BhdGggIgogIGRvbmU7ICAKZG9uZQoKIyBIb3cgbWFueSBmaWxlcz8KZmluZCAkc2VnbWVudHNfZGlyLyovKi5kYXRhLnR4dCB8IHdjIC1sCiMgODk1MQpmaW5kICRpbl9kaXIvKi8qXzEuZGF0YS50eHQgfCB3YyAtbAojIDQzNDEKZmluZCAkaW5fZGlyLyovKl8tMS5kYXRhLnR4dCB8IHdjIC1sCiMgNDYxMApgYGAKCiMjIFJ1biBhbmFseXNpcyBwaXBlbGluZSB3aXRoIGBzbmFrZW1ha2VgCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CnNubWtfcHJvaj0iaW50cm9ncmVzc2lvbiIKCm1vZHVsZSBsb2FkIHNpbmd1bGFyaXR5CmNvbmRhIGFjdGl2YXRlIHNuYWtlbWFrZQoKc25ha2VtYWtlIFwKIC0tam9icyA1MDAwIFwKIC0tbGF0ZW5jeS13YWl0IDEwMCBcCiAtLWNsdXN0ZXItY29uZmlnIGNvZGUvc25ha2VtYWtlLyRzbm1rX3Byb2ovY29uZmlnL2NsdXN0ZXIuanNvbiBcCiAtLWNsdXN0ZXIgJ2JzdWIgLWcgL3NuYWtlbWFrZV9iZ2VuaWUgLUoge2NsdXN0ZXIubmFtZX0gLW4ge2NsdXN0ZXIubn0gLU0ge2NsdXN0ZXIubWVtb3J5fSAtbyB7Y2x1c3Rlci5vdXRwdXR9IC1lIHtjbHVzdGVyLmVycm9yfScgXAogLS1rZWVwLWdvaW5nIFwKIC0tcmVydW4taW5jb21wbGV0ZSBcCiAtLXVzZS1jb25kYSBcCiAtLXVzZS1zaW5ndWxhcml0eSBcCiAtcyBjb2RlL3NuYWtlbWFrZS8kc25ta19wcm9qL1NuYWtlZmlsZSBcCiAtcApgYGAKCiMgKmYqIHN0YXRpc3RpYyBhbmFseXNpcwoKIyMgUmVhZCBpbiBkYXRhCgpgYGB7ciwgcmVzdWx0cyA9ICdhc2lzJ30KZGF0YV9maWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbnRyb2dyZXNzaW9uIiwgIjIwMjEwMzE1X2Zfc3RhdF9maW5hbC50eHQiKQojIFJlYWQgaW4gZGF0YQpmaW5hbF9kZiA8LSByZWFkLnRhYmxlKGRhdGFfZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgICAgYXMuaXMgPSBUKQoKZmluYWxfZGYgPC0gZmluYWxfZGYgJT4lIAogIGRwbHlyOjptdXRhdGUoYWNyb3NzKFAyLAogICAgICAgICAgICAgICAgICAgICAgIH5mYWN0b3IoLngsIGxldmVscyA9IGZpc2hfb3JkZXIpKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoY2hyID0gZmFjdG9yKGNociwgbGV2ZWxzID0gY2hyX29yZGVyKSkKCmtuaXRyOjprYWJsZShoZWFkKGZpbmFsX2RmKSkKYGBgCgoKIyMgQ3JlYXRlIERGIHdpdGggbWVhbiBgbWVsYXN0aWdtYWAgYW5kIGBqYXZhbmljdXNgCgpgYGB7ciwgcmVzdWx0cyA9ICdhc2lzJ30KY29yX2RmIDwtIGZpbmFsX2RmICU+JSAKICAjIGZpbHRlciBmb3Igd2hlbiBQMSBpcyBhbm90aGVyIE9yeXppYXMsIGFuZCBQMiAKICBkcGx5cjo6ZmlsdGVyKFAxICVpbiUgYygiamF2YW5pY3VzIiwgIm1lbGFzdGlnbWEiKSAmIFAyICE9ICJNSUtLIiAmIFAzID09ICJNSUtLIikgJT4lIAogICMgcGl2b3QgdG8gcHV0IHRoZSBhZG1peHR1cmVfZiBzdGF0IGZvciBtZWxhc3RpZ21hIGFuZCBqYXZhbmljdXMgaW4gdGhlIHNhbWUgcm93CiAgdGlkeXI6OnBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKCJQMiIsICJjaHIiKSwKICAgICAgICAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IFAxLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IGMoYWRtaXhfZiwgZl9jaV9sb3dlciwgZl9jaV91cHBlcikpCgpjb3JfZGYkY2hyIDwtIGFzLmNoYXJhY3Rlcihjb3JfZGYkY2hyKQpjb3JfZGYkY2hyIDwtIGlmZWxzZShjb3JfZGYkY2hyID09ICJhbGwiLCAiZ2Vub21lLXdpZGUiLCBjb3JfZGYkY2hyKQpjaHJfb3JkZXJfcGxvdCA8LSBjKHNlcSgxLDI0KSwgImdlbm9tZS13aWRlIikKY29yX2RmJGNociA8LSBmYWN0b3IoY29yX2RmJGNociwgbGV2ZWxzID0gY2hyX29yZGVyX3Bsb3QpCgpjb3JfZGZfbWVhbnMgPC0gY29yX2RmICU+JQogICMgYXBwbHkgYWNyb3NzIHJvd3MKICBkcGx5cjo6cm93d2lzZSgpICU+JSAKICAjIGdldCBtZWFucyBmb3IgZiBhbmQgQ0lzCiAgZHBseXI6Om11dGF0ZShtZWFuX2YgPSBtZWFuKGMoYWRtaXhfZl9qYXZhbmljdXMsIGFkbWl4X2ZfbWVsYXN0aWdtYSkpLAogICAgICAgICAgICAgICAgbWVhbl9jaV91cHBlciA9IG1lYW4oYyhmX2NpX3VwcGVyX2phdmFuaWN1cywgZl9jaV91cHBlcl9tZWxhc3RpZ21hKSksCiAgICAgICAgICAgICAgICBtZWFuX2NpX2xvd2VyID0gbWVhbihjKGZfY2lfbG93ZXJfamF2YW5pY3VzLCBmX2NpX2xvd2VyX21lbGFzdGlnbWEpKSkgJT4lIAogICMgc2V0IHN0YXRzIGF0IGEgbWF4aW11bSBvZiAxCiAgZHBseXI6Om11dGF0ZShhY3Jvc3MoYygibWVhbl9mIiwgIm1lYW5fY2lfdXBwZXIiLCAibWVhbl9jaV9sb3dlciIpLAogICAgICAgICAgICAgICAgICAgICAgIH5kcGx5cjo6aWZfZWxzZSgueCA+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC54KSkpCgprbml0cjo6a2FibGUoaGVhZChjb3JfZGZfbWVhbnMpKQpgYGAKCiMjIFBsb3QKCmBgYHtyfQpmc3RhdF9wbG90ID0gY29yX2RmX21lYW5zICU+JSAKICBnZ3Bsb3QoYWVzKFAyLCBtZWFuX2YsIGZpbGwgPSBQMikpICsKICAgIGdlb21fY29sKCkgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IG1lYW5fY2lfbG93ZXIsCiAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0gbWVhbl9jaV91cHBlciksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwKICAgICAgICAgICAgICAgICAgd2lkdGggPSAwLjI1KSArICAKICAgIGd1aWRlcyhmaWxsID0gRikgKwogICAgZmFjZXRfd3JhcCh+Y2hyKSArCiAgICB5bGltKDAsMSkgKwogICAgeWxhYihleHByZXNzaW9uKHBhc3RlKCJNZWFuICIsIGl0YWxpYygiZiIpLCAiIHN0YXRpc3RpYyIpKSkgKwogICAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4KSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxfYWJiYSkKCmZzdGF0X3Bsb3QKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9Cm91dF9maWxlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICIyMDIxMDMxNV9mX3N0YXQiKQoKIyBQTkcKZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUob3V0X2ZpbGUsICIucG5nIiwgc2VwID0gIiIpLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICB3aWR0aCA9IDI0Ljc1LAogICAgICAgaGVpZ2h0ID0gMTkuNSwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKCiMgU1ZHCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKG91dF9maWxlLCAiLnN2ZyIsIHNlcCA9ICIiKSwKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgd2lkdGggPSAyNC43NSwKICAgICAgIGhlaWdodCA9IDE5LjUsCiAgICAgICB1bml0cyA9ICJjbSIpCmBgYAoKIyBTbGlkaW5nIHdpbmRvd3MgQUJCQSBCQUJBCgojIyBSZWFkIGluIGRhdGEKCmBgYHtyLCBtZXNzYWdlID0gRn0KaW5fZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAiaW50cm9ncmVzc2lvbiIsICJhYmJhX3NsaWRpbmdfZmluYWwiLCAiNTAwMDBfMTAwLnR4dCIpCiMgUmVhZCBpbiBkYXRhCmRmID0gcmVhZHI6OnJlYWRfY3N2KGluX2ZpbGUpICU+JSAKICBkcGx5cjo6YXJyYW5nZShwMSwgcDIsIHNjYWZmb2xkLCBzdGFydCkKCiMgQ29udmVydCBmZCB0byAwIGlmIEQgPCAwCmRmJGZkID0gaWZlbHNlKGRmJEQgPCAwLAogICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICBkZiRmZCkKCiMgQ2hhbmdlIG5hbWVzCmRmID0gZGYgJT4lIAogIGRwbHlyOjptdXRhdGUocDIgPSByZWNvZGUoZGYkcDIsIGhkcnIgPSAiSGRyUiIsIGhuaSA9ICJITkkiLCBoc29rID0gIkhTT0siKSkKCgpgYGAKCiMjIFBsb3QKCiMjIyBTdGFuZGFyZAoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gMjB9CmRmICU+JSAKICBkcGx5cjo6ZmlsdGVyKHAxID09ICJtZWxhc3RpZ21hIikgJT4lIAogIGdncGxvdCgpICsKICAgIGdlb21fbGluZShhZXMobWlkLCBmZCwgY29sb3VyID0gcDIpKSArCiAgICBmYWNldF93cmFwKH5zY2FmZm9sZCwgbnJvdyA9IDI0LCBuY29sID0gMSkgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBwYWxfYWJiYSkgKwogICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTApICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDAsIDUwMDAwMDAsIDEwMDAwMDAwLCAxNTAwMDAwMCwgMjAwMDAwMDAsIDI1MDAwMDAwLCAzMDAwMDAwMCwgMzUwMDAwMDApLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICsKICAgIHhsYWIoIkJhc2UgcG9zaXRpb24iKSArCiAgICB5bGFiKGJxdW90ZShpdGFsaWMoZltkXSkpKSArCiAgICBsYWJzKGNvbG91ciA9ICJQMiIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpvdXRfZmlsZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTAzMTdfYWJiYV9zbGlkaW5nLnBuZyIpCgpnZ3NhdmUoZmlsZW5hbWUgPSBvdXRfZmlsZSwKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgd2lkdGggPSAyNC43NSwKICAgICAgIGhlaWdodCA9IDUwLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gMzAwKQpgYGAKCiMjIyBLYXJ5b3Bsb3QKCiMjIyMgTWFrZSBjdXN0b20gY2hyb21vc29tZSBzY2FmZm9sZAoKYGBge3J9CiMgR2V0IGNocm9tb3NvbWUgbGVuZ3RocwptZWRfY2hyX2xlbnMgPSByZWFkLnRhYmxlKGhlcmUoImRhdGEiLCAiT3J5emlhc19sYXRpcGVzLkFTTTIyMzQ2N3YxLmRuYS50b3BsZXZlbC5mYV9jaHJfY291bnRzLnR4dCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbC5uYW1lcyA9IGMoImNociIsICJlbmQiKSkKIyBBZGQgc3RhcnQKbWVkX2Nocl9sZW5zJHN0YXJ0ID0gMQojIFJlb3JkZXIKbWVkX2Nocl9sZW5zID0gbWVkX2Nocl9sZW5zICU+JSAKICBkcGx5cjo6c2VsZWN0KGNociwgc3RhcnQsIGVuZCkKIyBDcmVhdGUgY3VzdG9tIGdlbm9tZQptZWRfZ2Vub21lID0gcmVnaW9uZVI6OnRvR1JhbmdlcyhtZWRfY2hyX2xlbnMpCmBgYAoKIyMjIyAgUHJvY2VzcyBBQkJBIHNsaWRpbmcgd2luZG93cyBkYXRhCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHJlc3VsdHMgPSAnYXNpcyd9CmluX2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgImludHJvZ3Jlc3Npb24iLCAiYWJiYV9zbGlkaW5nX2ZpbmFsIiwgIjUwMDAwXzEwMC50eHQiKQojIFJlYWQgaW4gZGF0YQpkZiA9IHJlYWRyOjpyZWFkX2Nzdihpbl9maWxlKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UocDEsIHAyLCBzY2FmZm9sZCwgc3RhcnQpCgojIENvbnZlcnQgZmQgdG8gMCBpZiBEIDwgMApkZiRmZCA9IGlmZWxzZShkZiREIDwgMCwKICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgZGYkZmQpCgojIENoYW5nZSBuYW1lcwpkZiA9IGRmICU+JSAKICBkcGx5cjo6bXV0YXRlKHAyID0gcmVjb2RlKGRmJHAyLCBoZHJyID0gIkhkclIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpCgojIEdldCBkZiB3aXRoIG1lYW4gb2YgbWVsYXN0aWdtYS9qYXZhbmljdXMKZGZfa3AgPSBkZiAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoc2NhZmZvbGQsIHN0YXJ0LCBlbmQsIG1pZCwgcDIpLCBuYW1lc19mcm9tID0gcDEsIHZhbHVlc19mcm9tID0gZmQpICU+JQogICMgZ2V0IG1lYW4gb2YgbWVsYXN0aWdtYS9qYXZhbmljdXMKICBkcGx5cjo6bXV0YXRlKG1lYW5fZmQgPSByb3dNZWFucyhkcGx5cjo6c2VsZWN0KC4sIG1lbGFzdGlnbWEsIGphdmFuaWN1cyksIG5hLnJtID0gVCkpICU+JSAKICBkcGx5cjo6YXJyYW5nZShwMiwgc2NhZmZvbGQsIHN0YXJ0KQoKa25pdHI6OmthYmxlKGhlYWQoZGZfa3ApKQpgYGAKCiMjIyMgUmVhZCBpbiBTTlAgZGVuc2l0eSBkYXRhCgojIyMjIyBITkkgYW5kIEhTT0sKCmBgYHtyLCBldmFsID0gRn0KaW5fZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9obmlfaHNvay50eHQuZ3oiKQojIFJlYWQgaW4gZmlsZSBvbiBsb2NhbApvbF9yYW5nZXNfZGYgPSByZWFkLnRhYmxlKGluX2ZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuaXMgPSBUKQoKb2xfcmFuZ2VzX2RmX2xvbmcgPSBvbF9yYW5nZXNfZGYgJT4lIAogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IGMoaG5pLCBoc29rKSwgbmFtZXNfdG8gPSAibGluZSIsIHZhbHVlc190byA9ICJwcmVzZW50IikKCm9sX3Jhbmdlc19saXN0ID0gc3BsaXQob2xfcmFuZ2VzX2RmX2xvbmcsIGYgPSBvbF9yYW5nZXNfZGZfbG9uZyRsaW5lKQoKb2xfcmFuZ2VzX2xpc3QgPSBsYXBwbHkob2xfcmFuZ2VzX2xpc3QsIGZ1bmN0aW9uKHgpewogICMgcmVtb3ZlIE5BcwogIGRmID0geCAlPiUgCiAgICB0aWR5cjo6ZHJvcF9uYShwcmVzZW50KQogICMgY29udmVydCB0byBHUmFuZ2VzIG9iamVjdAogIG9sX3JhbmdlcyA9IEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShkZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlLnN0cmFuZCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcW5hbWVzLmZpZWxkID0gImNociIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0LmZpZWxkID0gInBvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZC5maWVsZCA9ICJwb3MiKQogIHJldHVybihvbF9yYW5nZXMpCn0pCgpgYGAKCmBgYHtyLCBldmFsID0gRiwgaW5jbHVkZSA9IEZ9CiMgU2F2ZSB0byBzcGVlZCB1cCB3aGVuIHJlbmRlcmluZyBIVE1MCnNhdmVSRFMob2xfcmFuZ2VzX2xpc3QsIGhlcmU6OmhlcmUoImRhdGEvaW50cm9ncmVzc2lvbi9obmlfaHNva19yYW5nZS5yZHMiKSkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9Cm9sX3Jhbmdlc19saXN0ID0gcmVhZFJEUyhoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vaG5pX2hzb2tfcmFuZ2UucmRzIikpCmBgYAoKIyMjIyMgTUlLSwoKYGBge3IsIGV2YWwgPSBGfQppbl9maWxlID0gaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL21pa2sudHh0Lmd6IikKIyBSZWFkIGluIGZpbGUgb24gbG9jYWwKbWlra19yYW5nZXNfZGYgPSByZWFkLnRhYmxlKGluX2ZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJjaHIiLCAicG9zIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5pcyA9IFQpCgojIENvbnZlcnQgdG8gR1JhbmdlcyBvYmplY3QKCm1pa2tfcmFuZ2VzID0gR2Vub21pY1Jhbmdlczo6bWFrZUdSYW5nZXNGcm9tRGF0YUZyYW1lKG1pa2tfcmFuZ2VzX2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmUuc3RyYW5kID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VxbmFtZXMuZmllbGQgPSAiY2hyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQuZmllbGQgPSAicG9zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kLmZpZWxkID0gInBvcyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGLCBpbmNsdWRlID0gRn0KIyBTYXZlIHRvIHNwZWVkIHVwIHdoZW4gcmVuZGVyaW5nIEhUTUwKc2F2ZVJEUyhtaWtrX3JhbmdlcywgaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL21pa2tfcmFuZ2UucmRzIikpCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGfQptaWtrX3JhbmdlcyA9IHJlYWRSRFMoaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL21pa2tfcmFuZ2UucmRzIikpCmBgYAoKIyMjIyBHZXQgZXhvbiBkZW5zaXR5CgpgYGB7ciwgZXZhbCA9IEZ9CiMgR2V0IGxpc3Qgb2YgZXhvbnMgZnJvbSBiaW9tYVJ0CgojIyBTZWxlY3QgZGF0YXNldApvbGF0X21hcnQgPSBiaW9tYVJ0Ojp1c2VFbnNlbWJsKGJpb21hcnQgPSAiZW5zZW1ibCIsIGRhdGFzZXQgPSAib2xhdGlwZXNfZ2VuZV9lbnNlbWJsIikKIyMgR2V0IGF0dHJpYnV0ZXMgb2YgaW50ZXJlc3QgKGV4b24gSUQsIGNociwgc3RhcnQsIGVuZCkKZXhvbnMgPC0gYmlvbWFSdDo6Z2V0Qk0oYXR0cmlidXRlcyA9IGMoImNocm9tb3NvbWVfbmFtZSIsICJlbnNlbWJsX2dlbmVfaWQiLCAiZW5zZW1ibF90cmFuc2NyaXB0X2lkIiwgInRyYW5zY3JpcHRfc3RhcnQiLCAidHJhbnNjcmlwdF9lbmQiLCAidHJhbnNjcmlwdF9sZW5ndGgiLCAiZW5zZW1ibF9leG9uX2lkIiwgInJhbmsiLCAic3RyYW5kIiwgImV4b25fY2hyb21fc3RhcnQiLCAiZXhvbl9jaHJvbV9lbmQiLCAiY2RzX3N0YXJ0IiwgImNkc19lbmQiKSwKICAgICAgICAgICAgICAgbWFydCA9IG9sYXRfbWFydCkKIyMgQ29udmVydCBleG9ucyB0byBHUmFuZ2VzCmV4X3JhbmdlcyA9IEdlbm9taWNSYW5nZXM6Om1ha2VHUmFuZ2VzRnJvbURhdGFGcmFtZShleG9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5zdHJhbmQgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VxbmFtZXMuZmllbGQgPSAiY2hyb21vc29tZV9uYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0LmZpZWxkID0gImV4b25fY2hyb21fc3RhcnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kLmZpZWxkID0gImV4b25fY2hyb21fZW5kIikKYGBgCgpgYGB7ciwgZXZhbCA9IEYsIGluY2x1ZGUgPSBGfQojIFNhdmUgdG8gc3BlZWQgdXAgd2hlbiByZW5kZXJpbmcgSFRNTApzYXZlUkRTKGV4X3JhbmdlcywgaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL2V4X3JhbmdlLnJkcyIpKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KZXhfcmFuZ2VzID0gcmVhZFJEUyhoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vZXhfcmFuZ2UucmRzIikpCmBgYAoKIyMjIyBBbGwgY2hyb21vc29tZXMKCmBgYHtyfQpmaWxlX291dCA9IGZpbGUucGF0aChwbG90c19kaXIsICIyMDIxMDMxOF9mZF93aXRoX2RlbnNpdHlfYWxsLnBuZyIpCmBgYAoKCmBgYHtyLCBldmFsID0gRn0KIyBTYXZlCnBuZyhmaWxlPWZpbGVfb3V0LAogICAgd2lkdGg9ODUwMCwKICAgIGhlaWdodD0xMzUwMCwKICAgIHVuaXRzID0gInB4IiwKICAgIHJlcyA9IDQwMCkKIyBQbG90IAprcCA9IHBsb3RLYXJ5b3R5cGUobWVkX2dlbm9tZSkKIyBBZGQgYmFzZSBudW1iZXJzIAprYXJ5b3Bsb3RlUjo6a3BBZGRCYXNlTnVtYmVycyhrcCwgdGljay5kaXN0ID0gNTAwMDAwMCwgY2V4ID0gMC4zKQojIEFkZCBkYXRhIGJhY2tncm91bmRzCmthcnlvcGxvdGVSOjprcERhdGFCYWNrZ3JvdW5kKGtwLCByMD0wLCByMSA9IDEsIGNvbG9yID0gIndoaXRlIikKIyBBZGQgYXhpcyBsYWJlbAprcEF4aXMoa3AsIHIwPTAuMywgcjEgPSAxLCBjZXggPSAwLjQpCiMgQWRkIGZkIGRhdGEKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSkKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJIZHJSIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiNGM0I2MUYiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSkKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHggPSBkZl9rcCRtaWRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgeSA9IGRmX2twJG1lYW5fZmRbZGZfa3AkcDIgPT0gIkhTT0siXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiM2MzFFNjgiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSkKIyBBZGQgU05QIGRlbnNpdHkgZGF0YQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW1pa2tfcmFuZ2VzLCBjb2wgPSAiIzQ5QTM3OSIsCiAgICAgICAgICAgICAgcjA9MCwgcjE9MC4xLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhuaSwgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4yLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhzb2ssIGNvbCA9ICIjNjMxRTY4IiwgCiAgICAgICAgICAgICAgcjA9MC4yLCByMT0wLjMsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCiNrcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhkcnIsIGNvbCA9ICIjRjNCNjFGIiwKIyAgICAgICAgICAgICAgcjA9MC40NSwgcjE9MC42LAojICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQojIEFkZCBleG9uIGRlbnNpdHkgdG8gaWRlb2dyYW0Ka3BQbG90RGVuc2l0eShrcCwgZGF0YT1leF9yYW5nZXMsIGNvbCA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgICBkYXRhLnBhbmVsID0gImlkZW9ncmFtIiwKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwLAogICAgICAgICAgICAgIHIwID0gMC41LCByMSA9IDEpCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9ZXhfcmFuZ2VzLCBjb2wgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICAgZGF0YS5wYW5lbCA9ICJpZGVvZ3JhbSIsCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCwKICAgICAgICAgICAgICByMCA9IDAuNSwgcjEgPSAwKQojIEFkZCBsYWJlbHMKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iTUlLSyIsCiAgICAgICAgICAgIHIwPTAsIHIxPTAuMDUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjQpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhOSSIsCiAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4xNSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjQpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhTT0siLAogICAgICAgICAgICByMD0wLjIsIHIxPTAuMjUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjQpCiNrcEFkZExhYmVscyhrcCwgbGFiZWxzPSJIZHJSIiwKIyAgICAgICAgICAgIHIwPTAuNDUsIHIxPTAuNiwgCiMgICAgICAgICAgICBjZXggPSAwLjQpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9YnF1b3RlKGl0YWxpYyhmW2RdKSksCiAgICAgICAgICAgIHIwPTAuMywgcjE9MSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDM1LAogICAgICAgICAgICBjZXggPSAwLjYpCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKGZpbGVfb3V0KSkKCmlmIChmaWxlLmV4aXN0cyhuZXdfcGF0aCkgIT0gVCl7CiAgZmlsZS5jb3B5KGZpbGVfb3V0LCBuZXdfcGF0aCkKfQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShmaWxlX291dCkpCmBgYAoKIyMjIyBDaHJvbW9zb21lIDQKCmBgYHtyfQpvdXRfZmlsZSA9IGZpbGUucGF0aChwbG90c19kaXIsICIyMDIxMDMxOF9mZF93aXRoX2RlbnNpdHlfY2hyXzQucG5nIikKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQpwbmcoZmlsZT1vdXRfZmlsZSwKICAgIHdpZHRoPTU1MDAsCiAgICBoZWlnaHQ9MTE4NiwKICAgIHVuaXRzID0gInB4IiwKICAgIHJlcyA9IDQwMCkKCiMgUGxvdCAKa3AgPSBwbG90S2FyeW90eXBlKG1lZF9nZW5vbWUsIGNocm9tb3NvbWVzID0gIjQiLCBjZXggPSAxLjUpCiMgQWRkIGJhc2UgbnVtYmVycyAKa2FyeW9wbG90ZVI6OmtwQWRkQmFzZU51bWJlcnMoa3AsIHRpY2suZGlzdCA9IDUwMDAwMDAsIGNleCA9IDAuNykKIyBBZGQgZGF0YSBiYWNrZ3JvdW5kcwprYXJ5b3Bsb3RlUjo6a3BEYXRhQmFja2dyb3VuZChrcCwgcjA9MCwgcjEgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpCiMgQWRkIGF4aXMgbGFiZWwKa3BBeGlzKGtwLCByMD0wLjMsIHIxID0gMSwgY2V4ID0gMC44KQojIEFkZCBmZCBkYXRhCmx3ZCA9IDIKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSwKICAgICAgICAgICAgICAgICAgICAgbHdkID0gbHdkKQprYXJ5b3Bsb3RlUjo6a3BMaW5lcyhrcCwKICAgICAgICAgICAgICAgICAgICAgY2hyID0gZGZfa3Akc2NhZmZvbGRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICB5ID0gZGZfa3AkbWVhbl9mZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICBjb2wgPSAiI0YzQjYxRiIsCiAgICAgICAgICAgICAgICAgICAgIHIwPTAuMywgcjEgPSAxLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSBsd2QpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSFNPSyJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjNjMxRTY4IiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IGx3ZCkKIyBBZGQgU05QIGRlbnNpdHkgZGF0YQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW1pa2tfcmFuZ2VzLCBjb2wgPSAiIzQ5QTM3OSIsCiAgICAgICAgICAgICAgcjA9MCwgcjE9MC4xLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhuaSwgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4yLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhzb2ssIGNvbCA9ICIjNjMxRTY4IiwgCiAgICAgICAgICAgICAgcjA9MC4yLCByMT0wLjMsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCiNrcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhkcnIsIGNvbCA9ICIjRjNCNjFGIiwKIyAgICAgICAgICAgICAgcjA9MC40NSwgcjE9MC42LAojICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQojIEFkZCBleG9uIGRlbnNpdHkgdG8gaWRlb2dyYW0Ka3BQbG90RGVuc2l0eShrcCwgZGF0YT1leF9yYW5nZXMsIGNvbCA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgICBkYXRhLnBhbmVsID0gImlkZW9ncmFtIiwKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwLAogICAgICAgICAgICAgIHIwID0gMC41LCByMSA9IDEpCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9ZXhfcmFuZ2VzLCBjb2wgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICAgZGF0YS5wYW5lbCA9ICJpZGVvZ3JhbSIsCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCwKICAgICAgICAgICAgICByMCA9IDAuNSwgcjEgPSAwKQojIEFkZCBsYWJlbHMKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iTUlLSyIsCiAgICAgICAgICAgIHIwPTAsIHIxPTAuMDUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhOSSIsCiAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4xNSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhTT0siLAogICAgICAgICAgICByMD0wLjIsIHIxPTAuMjUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCiNrcEFkZExhYmVscyhrcCwgbGFiZWxzPSJIZHJSIiwKIyAgICAgICAgICAgIHIwPTAuNDUsIHIxPTAuNiwgCiMgICAgICAgICAgICBjZXggPSAwLjQpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9YnF1b3RlKGl0YWxpYyhmW2RdKSksCiAgICAgICAgICAgIHIwPTAuMywgcjE9MSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDM1LAogICAgICAgICAgICBjZXggPSAxKQpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfZmlsZSkpCgppZiAoZmlsZS5leGlzdHMobmV3X3BhdGgpICE9IFQpewogIGZpbGUuY29weShvdXRfZmlsZSwgbmV3X3BhdGgpCn0KYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYmFzZW5hbWUob3V0X2ZpbGUpKQpgYGAKCiMgRmluYWwgZmlndXJlCgojIyBBQkJBIEJBQkEgZGlhZ3JhbQoKQ3JlYXRlZCB3aXRoIFtWZWN0cl0oaHR0cHM6Ly92ZWN0ci5jb20vKSBhbmQgc2F2ZWQgaGVyZTogYHBsb3RzL2ludHJvZ3Jlc3Npb24vMjAyMTAzMThfYWJiYV9kaWFncmFtLnN2Z2AKCiMjIENvbXBpbGUgYWxsCgpgYGB7ciwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTguOH0KYWJiYV9kaWFncmFtID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJhYmJhX2RpYWdyYW0ucG5nIikKdHJlZSA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAidHJlZV9vcnl6aWFzX3dpdGhfYW5jZXN0b3IucG5nIikKa2FyeW9fY2hyNCA9IGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTAzMThfZmRfd2l0aF9kZW5zaXR5X2Nocl80LnBuZyIpCgpmaW5hbF9hYmJhID0gZ2dkcmF3KCkgKwogIGRyYXdfaW1hZ2UodHJlZSwKICAgICAgICAgICAgeCA9IDAsIHkgPSAuNywgd2lkdGggPSAuNCwgaGVpZ2h0ID0gLjM1LCB2anVzdCA9IC4xLCBoanVzdCA9IC0uMSwgc2NhbGUgPSAxLjIpICsKICBkcmF3X2ltYWdlKGthcnlvX2NocjQsCiAgICAgICAgICAgICB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMC4zLCBzY2FsZSA9IDEuMikgKyAgIAogIGRyYXdfcGxvdChmc3RhdF9wbG90LAogICAgICAgICAgICAgeCA9IC40LCB5ID0gLjMsIHdpZHRoID0gLjYsIGhlaWdodCA9IC43KSArCiAgZHJhd19pbWFnZShhYmJhX2RpYWdyYW0sCiAgICAgICAgICB4ID0gMCwgeSA9IC4zLCB3aWR0aCA9IC40LCBoZWlnaHQgPSAuMzUsIHZqdXN0ID0gLS4wNSwgc2NhbGUgPSAxLjEpICsKICBkcmF3X3Bsb3RfbGFiZWwobGFiZWwgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiksIHNpemUgPSAxNiwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMCwgLjM4LCAwKSwgeSA9IGMoMSwgLjcsIDEsIC4zKSkgIAoKCmZpbmFsX2FiYmEKCgpgYGAKYGBge3IsIGV2YWwgPSBGfQpnZ3NhdmUoaGVyZTo6aGVyZShwbG90c19kaXIsICIyMDIxMDMxOF9maW5hbF9maWd1cmUucG5nIiksCiAgICAgICB3aWR0aCA9IDM1LAogICAgICAgaGVpZ2h0ID0gMjEuODc1LAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNTAwKQpgYGAKCiMgTmV3IGZpbmFsIGZpZ3VyZSB3aXRoIGNpcmNvcwoKIyMgQ2lyY29zCgojIyMgUmVhZCBpbiBkYXRhCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CnRhcmdldF9maWxlID0gaGVyZTo6aGVyZSgiZGF0YS9pbnRyb2dyZXNzaW9uL2FiYmFfc2xpZGluZ19maW5hbF93aXRoX2ljYWIvbWluLXNpdGVzLTI1MC50eHQiKQpgYGAKClNhbml0eSBjaGVjayB3aXRoIGNvdW50cyBvZiBzaXRlczoKCmBgYHtyfQpyZWFkcjo6cmVhZF9jc3YodGFyZ2V0X2ZpbGUpICU+JSAKICAjIGFkZCBzbGlkaW5nIHdpbmRvdyBsZW5ndGgKICBkcGx5cjo6bXV0YXRlKHdpbmRvd19sZW5ndGhfa2IgPSAoZW5kIC0gc3RhcnQgKyAxKSAvIDEwMDApICU+JSAKICAjIGZpbHRlciBmb3IgNTAwIGtiIHdpbmRvd3MKICBkcGx5cjo6ZmlsdGVyKHdpbmRvd19sZW5ndGhfa2IgPT0gNTAwKSAlPiUgCiAgZHBseXI6OmNvdW50KHAxLCBwMikKYGBgCgoKQXMgc3VnZ2VzdGVkIGJ5IFNpbW9uIE1hcnRpbiBoZXJlOiA8aHR0cHM6Ly9naXRodWIuY29tL3NpbW9uaG1hcnRpbi9nZW5vbWljc19nZW5lcmFsI2FiYmEtYmFiYS1zdGF0aXN0aWNzLWluLXNsaWRpbmctd2luZG93cz4KPiBmZCBnaXZlcyBtZWFuaW5nbGVzcyB2YWx1ZXMgKDwwIG9yID4xKSBpZiBEIGlzIG5lZ2F0aXZlLiBJZiB0aGVyZSBpcyBubyBleGNlc3Mgb2Ygc2hhcmVkIGRlcml2ZWQgYWxsZWxlcyBiZXR3ZWVuIFAyIGFuZCBQMyAoaW5kaWNhdGVkIGJ5IGEgcG9zaXRpdmUgRCksIHRoZW4gdGhlIGV4Y2VzcyBjYW5ub3QgYmUgcXVhbnRpZmllZC4gZmQgdmFsdWVzIGZvciB3aW5kb3dzIHdpdGggbmVnYXRpdmUgRCBzaG91bGQgdGhlcmVmb3JlIGVpdGhlciBiZSBkaXNjYXJkZWQgb3IgY29udmVydGVkIHRvIHplcm8sIGRlcGVuZGluZyBvbiB5b3VyIGh5cG90aGVzaXMuCgojIyMjIEhvdyBtYW55IHdpbmRvd3MgaGF2ZSBEID4gMD8gCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CnJlYWRyOjpyZWFkX2Nzdih0YXJnZXRfZmlsZSkgJT4lIAogICMgYWRkIHNsaWRpbmcgd2luZG93IGxlbmd0aAogIGRwbHlyOjptdXRhdGUod2luZG93X2xlbmd0aF9rYiA9IChlbmQgLSBzdGFydCArIDEpIC8gMTAwMCkgJT4lIAogICMgZmlsdGVyIGZvciA1MDAga2Igd2luZG93cwogIGRwbHlyOjpmaWx0ZXIod2luZG93X2xlbmd0aF9rYiA9PSA1MDApICU+JSAKICAjIHJlY29kZSBsaW5lcwogIGRwbHlyOjptdXRhdGUoYWNyb3NzKGMoInAxIiwgInAyIiksIH5mYWN0b3IoLngsIGxldmVscyA9IGMoImljYWIiLCAiaGRyciIsICJobmkiLCAiaHNvayIpKSksCiAgICAgICAgICAgICAgICBhY3Jvc3MoYygicDEiLCAicDIiKSwgfnJlY29kZSgueCwgaWNhYiA9ICJpQ2FiIiwgaGRyciA9ICJIZHJSIiwgaG5pID0gIkhOSSIsIGhzb2sgPSAiSFNPSyIpKSkgJT4lIAogIGRwbHlyOjpncm91cF9ieShwMSwgcDIpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKG5fcG9zX2QgPSBsZW5ndGgod2hpY2goRCA+IDApKSkgJT4lIAogIGdncGxvdCgpICsKICAgIGdlb21fY29sKGFlcyhwMiwgbl9wb3NfZCwgZmlsbCA9IHAyKSkgKwogICAgZmFjZXRfd3JhcCh+cDEpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbF9hYmJhKSArCiAgICB4bGFiKCJQMiIpICsKICAgIHlsYWIoIk51bWJlciBvZiB3aW5kb3dzIChzaXRlcykgd2l0aCBwb3NpdGl2ZSBEIikgKwogICAgZ2d0aXRsZSgiQ2hvaWNlIG9mIFAxIChpQ2FiIG9yIEhkclIpIikgKwogICAgdGhlbWVfY293cGxvdCgpICsKICAgIGxhYnMoZmlsbCA9ICJQMiIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMvaW50cm9ncmVzc2lvbi8yMDIxMDQyOV9wMV9oZHJyX3ZfaWNhYl9jb3VudHNfdmFsaWRfc2l0ZXMucG5nIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHdpZHRoPTE1LjY5LAogICAgICAgaGVpZ2h0PTEwLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNDAwKQpgYGAKCiMjIyMgRGlzdHJpYnV0aW9ucyBvZiAkZl9EJAoKYGBge3IsIG1lc3NhZ2UgPSBGfQpyZWFkcjo6cmVhZF9jc3YodGFyZ2V0X2ZpbGUpICU+JSAKICAjIGFkZCBzbGlkaW5nIHdpbmRvdyBsZW5ndGgKICBkcGx5cjo6bXV0YXRlKHdpbmRvd19sZW5ndGhfa2IgPSAoZW5kIC0gc3RhcnQgKyAxKSAvIDEwMDApICU+JSAKICAjIGZpbHRlciBmb3IgNTAwIGtiIHdpbmRvd3MKICBkcGx5cjo6ZmlsdGVyKHdpbmRvd19sZW5ndGhfa2IgPT0gNTAwKSAlPiUgCiAgIyByZWNvZGUgbGluZXMKICBkcGx5cjo6bXV0YXRlKGFjcm9zcyhjKCJwMSIsICJwMiIpLCB+ZmFjdG9yKC54LCBsZXZlbHMgPSBjKCJpY2FiIiwgImhkcnIiLCAiaG5pIiwgImhzb2siKSkpLAogICAgICAgICAgICAgICAgYWNyb3NzKGMoInAxIiwgInAyIiksIH5yZWNvZGUoLngsIGljYWIgPSAiaUNhYiIsIGhkcnIgPSAiSGRyUiIsIGhuaSA9ICJITkkiLCBoc29rID0gIkhTT0siKSkpICU+JQogICMgcmVtb3ZlIGFsbCByb3dzIHdoZXJlIEQgPCAwCiAgZHBseXI6OmZpbHRlcihEID4gMCkgJT4lIAogIGdncGxvdCgpICsKICAgIGdlb21faGlzdG9ncmFtKGFlcyhmZCwgZmlsbCA9IHAyKSwgYmlucyA9IDUwKSArCiAgICBmYWNldF93cmFwKHZhcnMocDEsIHAyKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsX2FiYmEpICsKICAgIHhsYWIoIlAyIikgKwojICAgIHlsYWIoIk51bWJlciBvZiB3aW5kb3dzIChzaXRlcykgd2l0aCBwb3NpdGl2ZSBEIikgKwogICAgZ2d0aXRsZShleHByZXNzaW9uKGl0YWxpYyhmW2RdKSkpICsKICAgIHRoZW1lX2Nvd3Bsb3QoKSAgCgpgYGAKYGBge3IsIGV2YWwgPSBGfQpnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMvaW50cm9ncmVzc2lvbi8yMDIxMDQyOV9wMV9oZHJyX3ZfaWNhYl9mZF9kaXN0cmlidXRpb24ucG5nIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHdpZHRoPTE1LjY5LAogICAgICAgaGVpZ2h0PTEwLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNDAwKQpgYGAKCiMjIyMgR2V0IG1lYW4gZmQgZm9yIGVhY2ggcG9wdWxhdGlvbgoKYGBge3IsIG1lc3NhZ2UgPSBGfQpyZWFkcjo6cmVhZF9jc3YodGFyZ2V0X2ZpbGUpICU+JSAKICAjIGFkZCBzbGlkaW5nIHdpbmRvdyBsZW5ndGgKICBkcGx5cjo6bXV0YXRlKHdpbmRvd19sZW5ndGhfa2IgPSAoZW5kIC0gc3RhcnQgKyAxKSAvIDEwMDApICU+JSAKICAjIGZpbHRlciBmb3IgNTAwIGtiIHdpbmRvd3MKICBkcGx5cjo6ZmlsdGVyKHdpbmRvd19sZW5ndGhfa2IgPT0gNTAwKSAlPiUgCiAgIyByZWNvZGUgbGluZXMKICBkcGx5cjo6bXV0YXRlKGFjcm9zcyhjKCJwMSIsICJwMiIpLCB+ZmFjdG9yKC54LCBsZXZlbHMgPSBjKCJpY2FiIiwgImhkcnIiLCAiaG5pIiwgImhzb2siKSkpLAogICAgICAgICAgICAgICAgYWNyb3NzKGMoInAxIiwgInAyIiksIH5yZWNvZGUoLngsIGljYWIgPSAiaUNhYiIsIGhkcnIgPSAiSGRyUiIsIGhuaSA9ICJITkkiLCBoc29rID0gIkhTT0siKSkpICU+JQogICMgcmVtb3ZlIGFsbCByb3dzIHdoZXJlIEQgPCAwCiAgZHBseXI6OmZpbHRlcihEID4gMCkgJT4lIAogIGRwbHlyOjpmaWx0ZXIocDEgPT0gIkhkclIiKSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KHAyKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShtZWFuKGZkKSkKYGBgCgoKYGBge3IsIG1lc3NhZ2UgPSBGfQptaWtrX2FiYmFfZmluYWwgPSByZWFkcjo6cmVhZF9jc3YodGFyZ2V0X2ZpbGUpICU+JSAKICAjIGFkZCBzbGlkaW5nIHdpbmRvdyBsZW5ndGgKICBkcGx5cjo6bXV0YXRlKHdpbmRvd19sZW5ndGhfa2IgPSAoZW5kIC0gc3RhcnQgKyAxKSAvIDEwMDApICU+JSAKICAjIGZpbHRlciBmb3IgNTAwIGtiIHdpbmRvd3MKICBkcGx5cjo6ZmlsdGVyKHdpbmRvd19sZW5ndGhfa2IgPT0gNTAwKSAlPiUgCiAgIyByZWNvZGUgYGZkYCBhcyAwIGlmIGBEYCBpcyBuZWdhdGl2ZQogIGRwbHlyOjptdXRhdGUoZmQgPSBpZmVsc2UoRCA8IDAsIDAsIGZkKSkKCiMgSXMgaUNhYiBvciBIZHJSIGNsb3NlciB0byBNSUtLPwptaWtrX2FiYmFfZmluYWwgJT4lIAogIGRwbHlyOjpmaWx0ZXIocDIgJWluJSBjKCJpY2FiIiwgImhkcnIiKSkgJT4lIAogIGRwbHlyOjpncm91cF9ieShwMSwgcDIpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKGxlbmd0aCh3aGljaChmZCA9PSAwKSkpCgoKYGBgClRoZXJlIGFyZSBmZXdlciAwcyB3aGVuIEhkclIgaXMgUDEsIHdoaWNoIHN1Z2dlc3RzIHRoYXQgaUNhYiBpcyBtb3JlIGNsb3NlbHkgcmVsYXRlZCB0byB0aGUgTUlLSyBwYW5lbC4gQnV0IHlvdSB3YW50IGEgUDEgdGhhdCBpcyBmdXJ0aGVyIGF3YXkgc28gdGhhdCB5b3UnbGwgZ2V0IG1vcmUgZGF0YSBwb2ludHMsIHdoaWNoIGlzIHdoeSB3ZSdsbCBsaWtlbHkgZ28gd2l0aCBIZHJSLiAKCmBgYHtyLCBtZXNzYWdlID0gRn0KbWlra19hYmJhX2ZpbmFsID0gbWlra19hYmJhX2ZpbmFsICU+JSAKICAjIHJlY29kZSBsaW5lcwogIGRwbHlyOjptdXRhdGUocDIgPSBmYWN0b3IocDIsIGxldmVscyA9IGMoImhkcnIiLCAiaWNhYiIsICJobmkiLCAiaHNvayIpKSwKICAgICAgICAgICAgICAgIHAyID0gcmVjb2RlKHAyLCBoZHJyID0gIkhkclIiLCBpY2FiID0gImlDYWIiLCBobmkgPSAiSE5JIiwgaHNvayA9ICJIU09LIikpICU+JSAKICBkcGx5cjo6YXJyYW5nZShwMiwgc2NhZmZvbGQsIHN0YXJ0KSAlPiUgCiAgZHBseXI6OnNlbGVjdChzY2FmZm9sZCwgbWlkXzEgPSBtaWQsIG1pZF8yID0gbWlkLCBmZCwgcDEsIHAyKSAlPiUgCiAgZHBseXI6Om11dGF0ZShzY2FmZm9sZCA9IHBhc3RlKCJjaHIiLCBzY2FmZm9sZCwgc2VwID0iIikpICU+JSAKICBzcGxpdCguLCBmID0gLiRwMSkgJT4lIAogIHB1cnJyOjptYXAoLiwgZnVuY3Rpb24oUDEpIHNwbGl0KFAxLCBmID0gUDEkcDIpKSAlPiUgCiAgIyBSZW1vdmUgZW1wdHkgZGF0YSBmcmFtZXMgZm9yIGhkcnItaGRyciBhbmQgaWNhYi1pY2FiIHBvcHVsYXRpb24gY29tYmluYXRpb25zCiAgcHVycnI6Om1hcCguLCBmdW5jdGlvbihQMSkgUDFbcHVycnI6Om1hcF9sZ2woUDEsIGZ1bmN0aW9uKFAyKSBucm93KFAyKSAhPSAwKV0pCgpgYGAKCiMjIyBQbG90CgpgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJpbnRyb2dyZXNzaW9uIiwgIjIwMjEwNDI3X2ludHJvZ3Jlc3Npb25fY2lyY29zX01JS0tfQUJCQV9wMS1oZHJyLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQp0YXJnZXRfbGlzdCA9IG1pa2tfYWJiYV9maW5hbFtbImhkcnIiXV0KCnBuZyhvdXRfcGxvdCwKICAgIHdpZHRoID0gMjAsCiAgICBoZWlnaHQgPSAyMCwKICAgIHVuaXRzID0gImNtIiwKICAgIHJlcyA9IDUwMCkKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgNikpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKIyBQcmludCBsYWJlbCBpbiBjZW50ZXIKdGV4dCgwLCAwLCAiTUlLSyBwYW5lbFxuaW50cm9ncmVzc2lvbiB3aXRoXG5pQ2FiLCBITkksXG5hbmRcbkhTT0siKQoKIyMjIyMjIyMjIyMjIyMjCiMgSW50cm9ncmVzc2lvbgojIyMjIyMjIyMjIyMjIyMKY291bnRlciA9IDAKCnB1cnJyOjptYXAodGFyZ2V0X2xpc3QsIGZ1bmN0aW9uKFAyKXsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAKICBjaXJjb3MuZ2Vub21pY1RyYWNrKFAyLAogICAgICBwYW5lbC5mdW4gPSBmdW5jdGlvbihyZWdpb24sIHZhbHVlLCAuLi4pewogICAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVbWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHBhbF9hYmJhW1tuYW1lcyh0YXJnZXRfbGlzdFtjb3VudGVyXSldXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZWEgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0ga2FyeW9wbG90ZVI6OmRhcmtlcihwYWxfYWJiYVtbbmFtZXModGFyZ2V0X2xpc3RbY291bnRlcl0pXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudCA9IDgwKSkKICAgICAgICAjIEFkZCBiYXNlbGluZQogICAgICAgIGNpcmNvcy54YXhpcyhoID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG1ham9yLnRpY2sgPSBGKQogICAgICB9LAogICAgICB0cmFjay5oZWlnaHQgPSAwLjEsCiAgICAgIGJnLmJvcmRlciA9IE5BLAogICAgICB5bGltID0gYygwLCAxKSkKICAKICAjIEFkZCBheGlzIGZvciBpbnRyb2dyZXNzaW9uCiAgY2lyY29zLnlheGlzKHNpZGUgPSAicmlnaHQiLAogICAgICAgICAgICAgYXQgPSBjKC41LCAxKSwKICAgICAgICAgICAgIGxhYmVscy5jZXggPSAwLjI1KnBhcigiY2V4IiksCiAgICAgICAgICAgICB0aWNrLmxlbmd0aCA9IDIKICAgICAgICAgICAgICkKICAKICAjIEFkZCB5LWF4aXMgbGFiZWwgZm9yIGludHJvZ3Jlc3Npb24KICBpZiAoY291bnRlciA9PSAyKSB7CiAgY2lyY29zLnRleHQoMCwgMC41LAogICAgICAgICAgICAgIGxhYmVscyA9IGV4cHJlc3Npb24oaXRhbGljKGZbZF0pKSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiMgICAgICAgICAgICAgIGZhY2luZyA9ICJjbG9ja3dpc2UiLAogICAgICAgICAgICAgIGFkaiA9IGMoMywgMC41KSwKICAgICAgICAgICAgICBjZXggPSAwLjQqcGFyKCJjZXgiKSkKICB9CiAgCiAgIyBBZGQgeS1heGlzIGxhYmVsIGZvciBpbnRyb2dyZXNzaW9uCiAgY2lyY29zLnRleHQoMCwgMC41LAogICAgICAgICAgICAgIGxhYmVscyA9IG5hbWVzKHRhcmdldF9saXN0KVtjb3VudGVyXSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsCiAgICAgICAgICAgICAgYWRqID0gYyguNSwgMCksCiAgICAgICAgICAgICAgY2V4ID0gMC42KnBhcigiY2V4IikpICAKfSkKCmNpcmNvcy5jbGVhcigpCgpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfcGxvdCkpCgpmaWxlLmNvcHkob3V0X3Bsb3QsIG5ld19wYXRoLCBvdmVyd3JpdGUgPSBUKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfcGxvdCkpCmBgYApgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJpbnRyb2dyZXNzaW9uIiwgIjIwMjEwNDI3X2ludHJvZ3Jlc3Npb25fY2lyY29zX01JS0tfQUJCQV9wMS1pY2FiLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQp0YXJnZXRfbGlzdCA9IG1pa2tfYWJiYV9maW5hbFtbImljYWIiXV0KCnBuZyhvdXRfcGxvdCwKICAgIHdpZHRoID0gMjAsCiAgICBoZWlnaHQgPSAyMCwKICAgIHVuaXRzID0gImNtIiwKICAgIHJlcyA9IDUwMCkKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgNikpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKIyBQcmludCBsYWJlbCBpbiBjZW50ZXIKdGV4dCgwLCAwLCAiTUlLSyBwYW5lbFxuaW50cm9ncmVzc2lvbiB3aXRoXG5IZHJSLCBITkksXG5hbmRcbkhTT0siKQoKIyMjIyMjIyMjIyMjIyMjCiMgSW50cm9ncmVzc2lvbgojIyMjIyMjIyMjIyMjIyMKY291bnRlciA9IDAKCnB1cnJyOjptYXAodGFyZ2V0X2xpc3QsIGZ1bmN0aW9uKFAyKXsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAKICBjaXJjb3MuZ2Vub21pY1RyYWNrKFAyLAogICAgICBwYW5lbC5mdW4gPSBmdW5jdGlvbihyZWdpb24sIHZhbHVlLCAuLi4pewogICAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVbWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHBhbF9hYmJhW1tuYW1lcyh0YXJnZXRfbGlzdFtjb3VudGVyXSldXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZWEgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0ga2FyeW9wbG90ZVI6OmRhcmtlcihwYWxfYWJiYVtbbmFtZXModGFyZ2V0X2xpc3RbY291bnRlcl0pXV0pKQogICAgICAgICMgQWRkIGJhc2VsaW5lCiAgICAgICAgY2lyY29zLnhheGlzKGggPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gRiwKICAgICAgICAgICAgICAgICAgICAgbWFqb3IudGljayA9IEYpCiAgICAgIH0sCiAgICAgIHRyYWNrLmhlaWdodCA9IDAuMSwKICAgICAgYmcuYm9yZGVyID0gTkEsCiAgICAgIHlsaW0gPSBjKDAsIDEpKQogIAogICMgQWRkIGF4aXMgZm9yIGludHJvZ3Jlc3Npb24KICBjaXJjb3MueWF4aXMoc2lkZSA9ICJyaWdodCIsCiAgICAgICAgICAgICBhdCA9IGMoLjUsIDEpLAogICAgICAgICAgICAgbGFiZWxzLmNleCA9IDAuMjUqcGFyKCJjZXgiKSwKICAgICAgICAgICAgIHRpY2subGVuZ3RoID0gMgogICAgICAgICAgICAgKQogIAogICMgQWRkIHktYXhpcyBsYWJlbCBmb3IgaW50cm9ncmVzc2lvbgogIGlmIChjb3VudGVyID09IDIpIHsKICBjaXJjb3MudGV4dCgwLCAwLjUsCiAgICAgICAgICAgICAgbGFiZWxzID0gZXhwcmVzc2lvbihpdGFsaWMoZltkXSkpLAogICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9ICJjaHIxIiwKIyAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsCiAgICAgICAgICAgICAgYWRqID0gYygzLCAwLjUpLAogICAgICAgICAgICAgIGNleCA9IDAuNCpwYXIoImNleCIpKQogIH0KICAKICAjIEFkZCB5LWF4aXMgbGFiZWwgZm9yIGludHJvZ3Jlc3Npb24KICBjaXJjb3MudGV4dCgwLCAwLjUsCiAgICAgICAgICAgICAgbGFiZWxzID0gbmFtZXModGFyZ2V0X2xpc3QpW2NvdW50ZXJdLAogICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9ICJjaHIxIiwKICAgICAgICAgICAgICBmYWNpbmcgPSAiY2xvY2t3aXNlIiwKICAgICAgICAgICAgICBhZGogPSBjKC41LCAwKSwKICAgICAgICAgICAgICBjZXggPSAwLjYqcGFyKCJjZXgiKSkgIAp9KQoKY2lyY29zLmNsZWFyKCkKCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKG91dF9wbG90KSkKCmZpbGUuY29weShvdXRfcGxvdCwgbmV3X3BhdGgsIG92ZXJ3cml0ZSA9IFQpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGJhc2VuYW1lKG91dF9wbG90KSkKYGBgCiMjIyBGaW5hbCBmb3IgcGFwZXIgKHdpdGggaUNhYiBhcyB5ZWxsb3cpCgpgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJpbnRyb2dyZXNzaW9uIiwgIjIwMjEwNTA1X2ludHJvZ3Jlc3Npb25fY2lyY29zX01JS0tfQUJCQV9wMS1oZHJyLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQp0YXJnZXRfbGlzdCA9IG1pa2tfYWJiYV9maW5hbFtbImhkcnIiXV0KCiMgUmVzZXQgcGFsZXR0ZQpwYWxfYWJiYSA8LSBjKCIjRjNCNjFGIiwgIiNGM0I2MUYiLCAiIzYzMUU2OCIsICIjRjY2NzNBIiwgIiNGMzNBNTYiLCAiIzU1QjZCMCIsICIjNjIxQjAwIikKbmFtZXMocGFsX2FiYmEpIDwtIGMoImlDYWIiLCAiSGRyUiIsICJIU09LIiwgIkhOSSIsICJtZWxhc3RpZ21hIiwgImphdmFuaWN1cyIsICJLYWdhIikKCnBuZyhvdXRfcGxvdCwKICAgIHdpZHRoID0gMjAsCiAgICBoZWlnaHQgPSAyMCwKICAgIHVuaXRzID0gImNtIiwKICAgIHJlcyA9IDUwMCkKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgNikpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKIyBQcmludCBsYWJlbCBpbiBjZW50ZXIKdGV4dCgwLCAwLCAiTUlLSyBwYW5lbFxuaW50cm9ncmVzc2lvbiB3aXRoXG5pQ2FiLCBITkksXG5hbmRcbkhTT0siKQoKIyMjIyMjIyMjIyMjIyMjCiMgSW50cm9ncmVzc2lvbgojIyMjIyMjIyMjIyMjIyMKY291bnRlciA9IDAKCnB1cnJyOjptYXAodGFyZ2V0X2xpc3QsIGZ1bmN0aW9uKFAyKXsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAKICBjaXJjb3MuZ2Vub21pY1RyYWNrKFAyLAogICAgICBwYW5lbC5mdW4gPSBmdW5jdGlvbihyZWdpb24sIHZhbHVlLCAuLi4pewogICAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVbWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHBhbF9hYmJhW1tuYW1lcyh0YXJnZXRfbGlzdFtjb3VudGVyXSldXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZWEgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyID0ga2FyeW9wbG90ZVI6OmRhcmtlcihwYWxfYWJiYVtbbmFtZXModGFyZ2V0X2xpc3RbY291bnRlcl0pXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudCA9IDgwKSkKICAgICAgICAjIEFkZCBiYXNlbGluZQogICAgICAgIGNpcmNvcy54YXhpcyhoID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG1ham9yLnRpY2sgPSBGKQogICAgICB9LAogICAgICB0cmFjay5oZWlnaHQgPSAwLjEsCiAgICAgIGJnLmJvcmRlciA9IE5BLAogICAgICB5bGltID0gYygwLCAxKSkKICAKICAjIEFkZCBheGlzIGZvciBpbnRyb2dyZXNzaW9uCiAgY2lyY29zLnlheGlzKHNpZGUgPSAicmlnaHQiLAogICAgICAgICAgICAgYXQgPSBjKC41LCAxKSwKICAgICAgICAgICAgIGxhYmVscy5jZXggPSAwLjI1KnBhcigiY2V4IiksCiAgICAgICAgICAgICB0aWNrLmxlbmd0aCA9IDIKICAgICAgICAgICAgICkKICAKICAjIEFkZCB5LWF4aXMgbGFiZWwgZm9yIGludHJvZ3Jlc3Npb24KICBpZiAoY291bnRlciA9PSAyKSB7CiAgY2lyY29zLnRleHQoMCwgMC41LAogICAgICAgICAgICAgIGxhYmVscyA9IGV4cHJlc3Npb24oaXRhbGljKGZbZF0pKSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiMgICAgICAgICAgICAgIGZhY2luZyA9ICJjbG9ja3dpc2UiLAogICAgICAgICAgICAgIGFkaiA9IGMoMywgMC41KSwKICAgICAgICAgICAgICBjZXggPSAwLjQqcGFyKCJjZXgiKSkKICB9CiAgCiAgIyBBZGQgeS1heGlzIGxhYmVsIGZvciBpbnRyb2dyZXNzaW9uCiAgY2lyY29zLnRleHQoMCwgMC41LAogICAgICAgICAgICAgIGxhYmVscyA9IG5hbWVzKHRhcmdldF9saXN0KVtjb3VudGVyXSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsCiAgICAgICAgICAgICAgYWRqID0gYyguNSwgMCksCiAgICAgICAgICAgICAgY2V4ID0gMC42KnBhcigiY2V4IikpICAKfSkKCmNpcmNvcy5jbGVhcigpCgpkZXYub2ZmKCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZ9CiMgY29weSB0byBzYW1lIGRpcmVjdG9yeSBhcyBjdXJyZW50IG5vdGVib29rCmN1cnJlbnRfZGlyID0gZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRTb3VyY2VFZGl0b3JDb250ZXh0KCkkcGF0aCkKCm5ld19wYXRoID0gZmlsZS5wYXRoKGN1cnJlbnRfZGlyLCBiYXNlbmFtZShvdXRfcGxvdCkpCgpmaWxlLmNvcHkob3V0X3Bsb3QsIG5ld19wYXRoLCBvdmVyd3JpdGUgPSBUKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfcGxvdCkpCmBgYAoKIyMgUmUtZG8gZmluYWwgZmlndXJlIChqdXN0IHRyZWUsIHNjaGVtYSwgYW5kIGNpcmNvcykKCmBgYHtyfQphYmJhX2RpYWdyYW0gPSBoZXJlOjpoZXJlKHBsb3RzX2RpciwgIjIwMjEwNTA1X2FiYmFfZGlhZ3JhbS5wbmciKQp0cmVlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXNfbGF0aXBlc193aXRoX2FuY2VzdG9yLnBuZyIpCmNpcmNvc19hYmJhID0gaGVyZTo6aGVyZShwbG90c19kaXIsICIyMDIxMDUwNV9pbnRyb2dyZXNzaW9uX2NpcmNvc19NSUtLX0FCQkFfcDEtaGRyci5wbmciKQoKZmluYWxfYWJiYSA9IGdnZHJhdygpICsKICBkcmF3X2ltYWdlKHRyZWUsCiAgICAgICAgICAgIHggPSAwLCB5ID0gLjUsIHdpZHRoID0gLjQsIGhlaWdodCA9IC41NSwgdmp1c3QgPSAwLCBoanVzdCA9IC0uMSwgc2NhbGUgPSAxLjIpICsgICAgCiAgZHJhd19pbWFnZShjaXJjb3NfYWJiYSwKICAgICAgICAgICAgIHggPSAuNCwgeSA9IDAsIHdpZHRoID0gLjYsIGhlaWdodCA9IDEsIHNjYWxlID0gMS4xLCB2anVzdCA9IDApICsKICBkcmF3X2ltYWdlKGFiYmFfZGlhZ3JhbSwKICAgICAgICAgIHggPSAwLCB5ID0gMCwgd2lkdGggPSAuNCwgaGVpZ2h0ID0gLjU1LCB2anVzdCA9IDAsIGhqdXN0ID0gLS4xMjUsIHNjYWxlID0gMS4yKSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiQSIsICJCIiwgIkMiKSwgc2l6ZSA9IDI1LAogICAgICAgICAgICAgICAgICB4ID0gYygwLCAwLCAuNCksIHkgPSBjKDEsIC42LCAxKSwgY29sb3IgPSAiIzRmMDk0MyIpICAKCgpmaW5hbF9hYmJhCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpnZ3NhdmUoaGVyZTo6aGVyZShwbG90c19kaXIsICIyMDIxMDUwNV9pbnRyb2dyZXNzaW9uX2ZpbmFsX2ZpZ3VyZS5wbmciKSwKICAgICAgIHdpZHRoID0gMzUsCiAgICAgICBoZWlnaHQgPSAyMS44NzUsCiAgICAgICB1bml0cyA9ICJjbSIsCiAgICAgICBkcGkgPSA1MDApCmBgYAoKIyMgUmUtZG8gZmluYWwgZmlndXJlCgojIyMgQ2hyMgoKIyMjIyBSZWFkIGluIG5ldyBkYXRhCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHJlc3VsdHMgPSAnYXNpcyd9CmluX2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL2ludHJvZ3Jlc3Npb24vYWJiYV9zbGlkaW5nX2ZpbmFsX25vXzEzMS0xIiwgIjUwMDAwMF8yNTAudHh0IikKIyBSZWFkIGluIGRhdGEKZGYgPSByZWFkcjo6cmVhZF9jc3YoaW5fZmlsZSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKHAxLCBwMiwgc2NhZmZvbGQsIHN0YXJ0KQoKIyBDb252ZXJ0IGZkIHRvIDAgaWYgRCA8IDAKZGYkZmQgPSBpZmVsc2UoZGYkRCA8IDAsCiAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgIGRmJGZkKQoKIyBDaGFuZ2UgbmFtZXMKZGYgPSBkZiAlPiUgCiAgZHBseXI6Om11dGF0ZShwMiA9IHJlY29kZShkZiRwMiwgaGRyciA9ICJIZHJSIiwgaG5pID0gIkhOSSIsIGhzb2sgPSAiSFNPSyIpKQoKIyBHZXQgZGYgd2l0aCBtZWFuIG9mIG1lbGFzdGlnbWEvamF2YW5pY3VzCmRmX2twID0gZGYgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKHNjYWZmb2xkLCBzdGFydCwgZW5kLCBtaWQsIHAyKSwgbmFtZXNfZnJvbSA9IHAxLCB2YWx1ZXNfZnJvbSA9IGZkKSAlPiUKICAjIGdldCBtZWFuIG9mIG1lbGFzdGlnbWEvamF2YW5pY3VzCiAgZHBseXI6Om11dGF0ZShtZWFuX2ZkID0gcm93TWVhbnMoZHBseXI6OnNlbGVjdCguLCBtZWxhc3RpZ21hLCBqYXZhbmljdXMpLCBuYS5ybSA9IFQpKSAlPiUgCiAgZHBseXI6OmFycmFuZ2UocDIsIHNjYWZmb2xkLCBzdGFydCkKCmtuaXRyOjprYWJsZShoZWFkKGRmX2twKSkKYGBgCgojIyMjIFBsb3QKCiMjIyMjIGNocjQKCmBgYHtyfQpvdXRfZmlsZSA9IGZpbGUucGF0aChwbG90c19kaXIsICIyMDIxMDQwOV9mZF93aXRoX2RlbnNpdHlfY2hyXzRfNTAwa2Itd2luZG93LnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpwbmcoZmlsZT1vdXRfZmlsZSwKICAgIHdpZHRoPTU1MDAsCiAgICBoZWlnaHQ9MTE4NiwKICAgIHVuaXRzID0gInB4IiwKICAgIHJlcyA9IDQwMCkKCiMgUGxvdCAKa3AgPSBwbG90S2FyeW90eXBlKG1lZF9nZW5vbWUsIGNocm9tb3NvbWVzID0gIjQiLCBjZXggPSAxLjUpCiMgQWRkIGJhc2UgbnVtYmVycyAKa2FyeW9wbG90ZVI6OmtwQWRkQmFzZU51bWJlcnMoa3AsIHRpY2suZGlzdCA9IDUwMDAwMDAsIGNleCA9IDAuNykKIyBBZGQgZGF0YSBiYWNrZ3JvdW5kcwprYXJ5b3Bsb3RlUjo6a3BEYXRhQmFja2dyb3VuZChrcCwgcjA9MCwgcjEgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpCiMgQWRkIGF4aXMgbGFiZWwKa3BBeGlzKGtwLCByMD0wLjMsIHIxID0gMSwgY2V4ID0gMC44KQojIEFkZCBmZCBkYXRhCmx3ZCA9IDIKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSwKICAgICAgICAgICAgICAgICAgICAgbHdkID0gbHdkKQprYXJ5b3Bsb3RlUjo6a3BMaW5lcyhrcCwKICAgICAgICAgICAgICAgICAgICAgY2hyID0gZGZfa3Akc2NhZmZvbGRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICB5ID0gZGZfa3AkbWVhbl9mZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICBjb2wgPSAiI0YzQjYxRiIsCiAgICAgICAgICAgICAgICAgICAgIHIwPTAuMywgcjEgPSAxLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSBsd2QpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSFNPSyJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjNjMxRTY4IiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IGx3ZCkKIyBBZGQgU05QIGRlbnNpdHkgZGF0YQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW1pa2tfcmFuZ2VzLCBjb2wgPSAiIzQ5QTM3OSIsCiAgICAgICAgICAgICAgcjA9MCwgcjE9MC4xLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhuaSwgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4yLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhzb2ssIGNvbCA9ICIjNjMxRTY4IiwgCiAgICAgICAgICAgICAgcjA9MC4yLCByMT0wLjMsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCiNrcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhkcnIsIGNvbCA9ICIjRjNCNjFGIiwKIyAgICAgICAgICAgICAgcjA9MC40NSwgcjE9MC42LAojICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQojIEFkZCBleG9uIGRlbnNpdHkgdG8gaWRlb2dyYW0Ka3BQbG90RGVuc2l0eShrcCwgZGF0YT1leF9yYW5nZXMsIGNvbCA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgICBkYXRhLnBhbmVsID0gImlkZW9ncmFtIiwKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwLAogICAgICAgICAgICAgIHIwID0gMC41LCByMSA9IDEpCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9ZXhfcmFuZ2VzLCBjb2wgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICAgZGF0YS5wYW5lbCA9ICJpZGVvZ3JhbSIsCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCwKICAgICAgICAgICAgICByMCA9IDAuNSwgcjEgPSAwKQojIEFkZCBsYWJlbHMKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iTUlLSyIsCiAgICAgICAgICAgIHIwPTAsIHIxPTAuMDUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhOSSIsCiAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4xNSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhTT0siLAogICAgICAgICAgICByMD0wLjIsIHIxPTAuMjUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCgprcEFkZExhYmVscyhrcCwgbGFiZWxzPWJxdW90ZShpdGFsaWMoZltkXSkpLAogICAgICAgICAgICByMD0wLjMsIHIxPTEsIAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAzNSwKICAgICAgICAgICAgY2V4ID0gMSkKZGV2Lm9mZigpCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGfQojIGNvcHkgdG8gc2FtZSBkaXJlY3RvcnkgYXMgY3VycmVudCBub3RlYm9vawpjdXJyZW50X2RpciA9IGRpcm5hbWUocnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGgpCgpuZXdfcGF0aCA9IGZpbGUucGF0aChjdXJyZW50X2RpciwgYmFzZW5hbWUob3V0X2ZpbGUpKQoKZmlsZS5jb3B5KG91dF9maWxlLCBuZXdfcGF0aCwgb3ZlcndyaXRlID0gVCkKCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGJhc2VuYW1lKG91dF9maWxlKSkKYGBgCiMjIyMjIGNocjIKCmBgYHtyfQpvdXRfZmlsZSA9IGZpbGUucGF0aChwbG90c19kaXIsICIyMDIxMDQwOV9mZF93aXRoX2RlbnNpdHlfY2hyXzJfNTAwa2Itd2luZG93LnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpwbmcoZmlsZT1vdXRfZmlsZSwKICAgIHdpZHRoPTU1MDAsCiAgICBoZWlnaHQ9MTE4NiwKICAgIHVuaXRzID0gInB4IiwKICAgIHJlcyA9IDQwMCkKCiMgUGxvdCAKa3AgPSBwbG90S2FyeW90eXBlKG1lZF9nZW5vbWUsIGNocm9tb3NvbWVzID0gIjIiLCBjZXggPSAxLjUpCiMgQWRkIGJhc2UgbnVtYmVycyAKa2FyeW9wbG90ZVI6OmtwQWRkQmFzZU51bWJlcnMoa3AsIHRpY2suZGlzdCA9IDUwMDAwMDAsIGNleCA9IDAuNykKIyBBZGQgZGF0YSBiYWNrZ3JvdW5kcwprYXJ5b3Bsb3RlUjo6a3BEYXRhQmFja2dyb3VuZChrcCwgcjA9MCwgcjEgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpCiMgQWRkIGF4aXMgbGFiZWwKa3BBeGlzKGtwLCByMD0wLjMsIHIxID0gMSwgY2V4ID0gMC44KQojIEFkZCBmZCBkYXRhCmx3ZCA9IDIKa2FyeW9wbG90ZVI6OmtwTGluZXMoa3AsCiAgICAgICAgICAgICAgICAgICAgIGNociA9IGRmX2twJHNjYWZmb2xkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSE5JIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJITkkiXSwKICAgICAgICAgICAgICAgICAgICAgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgICAgICAgICByMD0wLjMsIHIxID0gMSwKICAgICAgICAgICAgICAgICAgICAgbHdkID0gbHdkKQprYXJ5b3Bsb3RlUjo6a3BMaW5lcyhrcCwKICAgICAgICAgICAgICAgICAgICAgY2hyID0gZGZfa3Akc2NhZmZvbGRbZGZfa3AkcDIgPT0gIkhkclIiXSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGRmX2twJG1pZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICB5ID0gZGZfa3AkbWVhbl9mZFtkZl9rcCRwMiA9PSAiSGRyUiJdLAogICAgICAgICAgICAgICAgICAgICBjb2wgPSAiI0YzQjYxRiIsCiAgICAgICAgICAgICAgICAgICAgIHIwPTAuMywgcjEgPSAxLAogICAgICAgICAgICAgICAgICAgICBsd2QgPSBsd2QpCmthcnlvcGxvdGVSOjprcExpbmVzKGtwLAogICAgICAgICAgICAgICAgICAgICBjaHIgPSBkZl9rcCRzY2FmZm9sZFtkZl9rcCRwMiA9PSAiSFNPSyJdLAogICAgICAgICAgICAgICAgICAgICB4ID0gZGZfa3AkbWlkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIHkgPSBkZl9rcCRtZWFuX2ZkW2RmX2twJHAyID09ICJIU09LIl0sCiAgICAgICAgICAgICAgICAgICAgIGNvbCA9ICIjNjMxRTY4IiwKICAgICAgICAgICAgICAgICAgICAgcjA9MC4zLCByMSA9IDEsCiAgICAgICAgICAgICAgICAgICAgIGx3ZCA9IGx3ZCkKIyBBZGQgU05QIGRlbnNpdHkgZGF0YQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW1pa2tfcmFuZ2VzLCBjb2wgPSAiIzQ5QTM3OSIsCiAgICAgICAgICAgICAgcjA9MCwgcjE9MC4xLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhuaSwgY29sID0gIiNGNjY3M0EiLAogICAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4yLCAKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQprcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhzb2ssIGNvbCA9ICIjNjMxRTY4IiwgCiAgICAgICAgICAgICAgcjA9MC4yLCByMT0wLjMsIAogICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gMjUwMDApCiNrcFBsb3REZW5zaXR5KGtwLCBkYXRhPW9sX3Jhbmdlc19saXN0JGhkcnIsIGNvbCA9ICIjRjNCNjFGIiwKIyAgICAgICAgICAgICAgcjA9MC40NSwgcjE9MC42LAojICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwKQojIEFkZCBleG9uIGRlbnNpdHkgdG8gaWRlb2dyYW0Ka3BQbG90RGVuc2l0eShrcCwgZGF0YT1leF9yYW5nZXMsIGNvbCA9ICIjZjc3Y2I1IiwKICAgICAgICAgICAgICBkYXRhLnBhbmVsID0gImlkZW9ncmFtIiwKICAgICAgICAgICAgICB3aW5kb3cuc2l6ZSA9IDI1MDAwLAogICAgICAgICAgICAgIHIwID0gMC41LCByMSA9IDEpCmtwUGxvdERlbnNpdHkoa3AsIGRhdGE9ZXhfcmFuZ2VzLCBjb2wgPSAiI2Y3N2NiNSIsCiAgICAgICAgICAgICAgZGF0YS5wYW5lbCA9ICJpZGVvZ3JhbSIsCiAgICAgICAgICAgICAgd2luZG93LnNpemUgPSAyNTAwMCwKICAgICAgICAgICAgICByMCA9IDAuNSwgcjEgPSAwKQojIEFkZCBsYWJlbHMKa3BBZGRMYWJlbHMoa3AsIGxhYmVscz0iTUlLSyIsCiAgICAgICAgICAgIHIwPTAsIHIxPTAuMDUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhOSSIsCiAgICAgICAgICAgIHIwPTAuMSwgcjE9MC4xNSwgCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCmtwQWRkTGFiZWxzKGtwLCBsYWJlbHM9IkhTT0siLAogICAgICAgICAgICByMD0wLjIsIHIxPTAuMjUsCiAgICAgICAgICAgIGxhYmVsLm1hcmdpbiA9IDAuMDAxLAogICAgICAgICAgICBjZXggPSAwLjUpCgprcEFkZExhYmVscyhrcCwgbGFiZWxzPWJxdW90ZShpdGFsaWMoZltkXSkpLAogICAgICAgICAgICByMD0wLjMsIHIxPTEsIAogICAgICAgICAgICBsYWJlbC5tYXJnaW4gPSAwLjAzNSwKICAgICAgICAgICAgY2V4ID0gMSkKZGV2Lm9mZigpCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGfQojIGNvcHkgdG8gc2FtZSBkaXJlY3RvcnkgYXMgY3VycmVudCBub3RlYm9vawpjdXJyZW50X2RpciA9IGRpcm5hbWUocnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGgpCgpuZXdfcGF0aCA9IGZpbGUucGF0aChjdXJyZW50X2RpciwgYmFzZW5hbWUob3V0X2ZpbGUpKQoKZmlsZS5jb3B5KG91dF9maWxlLCBuZXdfcGF0aCwgb3ZlcndyaXRlID0gVCkKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYmFzZW5hbWUob3V0X2ZpbGUpKQpgYGAKVXNlIGNocjQuCgojIyMgQ29tcG9zZSBmaW5hbCBmaWd1cmUKCmBgYHtyfQphYmJhX2RpYWdyYW0gPSBoZXJlOjpoZXJlKHBsb3RzX2RpciwgImFiYmFfZGlhZ3JhbS5wbmciKQp0cmVlID0gaGVyZTo6aGVyZShwbG90c19kaXIsICJ0cmVlX29yeXppYXNfd2l0aF9hbmNlc3Rvci5wbmciKQprYXJ5b19jaHI0ID0gaGVyZTo6aGVyZShwbG90c19kaXIsICIyMDIxMDQwOV9mZF93aXRoX2RlbnNpdHlfY2hyXzRfNTAwa2Itd2luZG93LnBuZyIpCmNpcmNvc19hYmJhID0gaGVyZTo6aGVyZShwbG90c19kaXIsICIyMDIxMDQwOV9pbnRyb2dyZXNzaW9uX2NpcmNvc19NSUtLX0FCQkEucG5nIikKCmZpbmFsX2FiYmEgPSBnZ2RyYXcoKSArCiAgZHJhd19pbWFnZSh0cmVlLAogICAgICAgICAgICB4ID0gMCwgeSA9IC43LCB3aWR0aCA9IC40LCBoZWlnaHQgPSAuMzUsIHZqdXN0ID0gLjEsIGhqdXN0ID0gLS4xLCBzY2FsZSA9IDEuMikgKwogIGRyYXdfaW1hZ2Uoa2FyeW9fY2hyNCwKICAgICAgICAgICAgIHggPSAwLCB5ID0gMCwgd2lkdGggPSAxLCBoZWlnaHQgPSAwLjMsIHNjYWxlID0gMS4yKSArICAKICBkcmF3X2ltYWdlKGNpcmNvc19hYmJhLAogICAgICAgICAgICAgeCA9IC40LCB5ID0gLjMsIHdpZHRoID0gLjYsIGhlaWdodCA9IC43LCBzY2FsZSA9IDEuMTUsIHZqdXN0ID0gLjAyNSkgKwogIGRyYXdfaW1hZ2UoYWJiYV9kaWFncmFtLAogICAgICAgICAgeCA9IDAsIHkgPSAuMywgd2lkdGggPSAuNCwgaGVpZ2h0ID0gLjM1LCB2anVzdCA9IC0uMDUsIHNjYWxlID0gMS4xKSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiQSIsICJCIiwgIkMiLCAiRCIpLCBzaXplID0gMjUsCiAgICAgICAgICAgICAgICAgIHggPSBjKDAsIDAsIC40NSwgMCksIHkgPSBjKDEsIC43LCAxLCAuMyksIGNvbG9yID0gIiM0ZjA5NDMiKSAgCgoKZmluYWxfYWJiYQpgYGAKCmBgYHtyLCBldmFsID0gRn0KZ2dzYXZlKGhlcmU6OmhlcmUocGxvdHNfZGlyLCAiMjAyMTA0MDlfaW50cm9ncmVzc2lvbl9maW5hbF9maWd1cmUucG5nIiksCiAgICAgICB3aWR0aCA9IDM1LAogICAgICAgaGVpZ2h0ID0gMjEuODc1LAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNTAwKQpgYGAKCg==